From 2985cd9a3a04acfe069c063c65ebf487a1413388 Mon Sep 17 00:00:00 2001
From: Dan Prince <dprince@redhat.com>
Date: Wed, 23 Nov 2016 10:39:11 -0500
Subject: [PATCH] Apply os-net-config with a script instead of element

Wire in os-net-config via a normal script heat deployment, which has the
following advantages:

1. Improved error path, currently o-a-c deployments don't report any
errors, thus hang and eventually the deployment times out

2. It's far more hackable from a deployer perspective, e.g it's
much easier to change the os-net-config options or include a
mapping file

3. Reduces our dependencies on o-a-c (it's only os-net-config and hiera
which requires it), although the script does currently still use oac to
get the metadata IP.

4. May enable passing os-net-config yaml via a json parameter in future,
reducing the need for resource_registry mappings (although we'll have to
support that for backwards compatibility)

The script used is based directly on 20-os-net-config (from t-i-e
at cf94c5e, we can probably improve this now that we have an error path,
but for this initial commit it's a straight copy other than the changes to
replace o-a-c for rendering the json config file.

Co-Authored-By: Steven Hardy <shardy@redhat.com>

Change-Id: I0ed08332cfc49a579de2e83960f0d8047690b97a
---
 net-config-bond.yaml                          |  63 ++---
 net-config-bridge.yaml                        |  36 +--
 net-config-linux-bridge.yaml                  |  60 ++---
 ...nfig-static-bridge-with-external-dhcp.yaml |  69 +++---
 net-config-static-bridge.yaml                 |  67 +++---
 net-config-static.yaml                        |  58 ++---
 .../config/bond-with-vlans/ceph-storage.yaml  | 121 +++++-----
 .../bond-with-vlans/cinder-storage.yaml       | 131 ++++++-----
 .../config/bond-with-vlans/compute-dpdk.yaml  | 155 ++++++-------
 network/config/bond-with-vlans/compute.yaml   | 131 ++++++-----
 .../controller-no-external.yaml               | 141 ++++++-----
 .../config/bond-with-vlans/controller-v6.yaml | 163 +++++++------
 .../config/bond-with-vlans/controller.yaml    | 153 ++++++------
 .../config/bond-with-vlans/swift-storage.yaml | 131 ++++++-----
 .../config/multiple-nics/ceph-storage.yaml    |  88 ++++---
 .../config/multiple-nics/cinder-storage.yaml  | 101 ++++----
 network/config/multiple-nics/compute.yaml     | 106 ++++-----
 .../config/multiple-nics/controller-v6.yaml   | 151 ++++++------
 network/config/multiple-nics/controller.yaml  | 142 ++++++------
 .../config/multiple-nics/swift-storage.yaml   | 101 ++++----
 .../ceph-storage.yaml                         |  95 ++++----
 .../cinder-storage.yaml                       | 109 +++++----
 .../compute.yaml                              | 113 +++++----
 .../controller-v6.yaml                        | 152 ++++++------
 .../controller.yaml                           | 149 ++++++------
 .../swift-storage.yaml                        | 109 +++++----
 .../config/single-nic-vlans/ceph-storage.yaml |  87 ++++---
 .../single-nic-vlans/cinder-storage.yaml      |  97 ++++----
 network/config/single-nic-vlans/compute.yaml  |  97 ++++----
 .../controller-no-external.yaml               | 107 +++++----
 .../single-nic-vlans/controller-v6.yaml       | 126 +++++-----
 .../config/single-nic-vlans/controller.yaml   | 117 +++++-----
 .../single-nic-vlans/swift-storage.yaml       |  97 ++++----
 network/scripts/run-os-net-config.sh          | 136 +++++++++++
 tools/yaml-nic-config-2-script.py             | 219 ++++++++++++++++++
 35 files changed, 2137 insertions(+), 1841 deletions(-)
 create mode 100755 network/scripts/run-os-net-config.sh
 create mode 100755 tools/yaml-nic-config-2-script.py

diff --git a/net-config-bond.yaml b/net-config-bond.yaml
index 01f8ac1da7..db6ff2c714 100644
--- a/net-config-bond.yaml
+++ b/net-config-bond.yaml
@@ -1,20 +1,22 @@
-heat_template_version: 2016-10-14
-
+heat_template_version: '2016-10-14'
 description: >
   Software Config to drive os-net-config with 2 bonded nics on a bridge.
-
 parameters:
   BondInterfaceOvsOptions:
     default: ''
-    description: |
-      The ovs_options string for the bond interface. Set things like
+    description: 'The ovs_options string for the bond interface. Set things like
+
       lacp=active and/or bond_mode=balance-slb using this option.
+
+      '
     type: string
     constraints:
-      - allowed_pattern: "^((?!balance.tcp).)*$"
-        description: |
-          The balance-tcp bond mode is known to cause packet loss and
-          should not be used in BondInterfaceOvsOptions.
+    - allowed_pattern: ^((?!balance.tcp).)*$
+      description: 'The balance-tcp bond mode is known to cause packet loss and
+
+        should not be used in BondInterfaceOvsOptions.
+
+        '
   ControlPlaneIp:
     default: ''
     description: IP address/subnet on the ctlplane network
@@ -43,34 +45,35 @@ parameters:
     default: ''
     description: IP address/subnet on the management network
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: ovs_bridge
-              name: {get_input: bridge_name}
-              use_dhcp: true
-              members:
-                -
-                  type: ovs_bond
+        str_replace:
+          template:
+            get_file: network/scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: ovs_bridge
+                name: bridge_name
+                use_dhcp: true
+                members:
+                - type: ovs_bond
                   name: bond1
                   use_dhcp: true
-                  ovs_options: {get_param: BondInterfaceOvsOptions}
+                  ovs_options:
+                    get_param: BondInterfaceOvsOptions
                   members:
-                    -
-                      type: interface
-                      name: nic1
-                    -
-                      type: interface
-                      name: nic2
-
+                  - type: interface
+                    name: nic1
+                  - type: interface
+                    name: nic2
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/net-config-bridge.yaml b/net-config-bridge.yaml
index 318eca8af8..e7b966953b 100644
--- a/net-config-bridge.yaml
+++ b/net-config-bridge.yaml
@@ -1,8 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
   Software Config to drive os-net-config for a simple bridge.
-
 parameters:
   ControlPlaneIp:
     default: ''
@@ -32,27 +30,29 @@ parameters:
     default: ''
     description: IP address/subnet on the management network
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: ovs_bridge
-              name: {get_input: bridge_name}
-              use_dhcp: true
-              members:
-                -
-                  type: interface
-                  name: {get_input: interface_name}
+        str_replace:
+          template:
+            get_file: network/scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: ovs_bridge
+                name: bridge_name
+                use_dhcp: true
+                members:
+                - type: interface
+                  name: interface_name
                   # force the MAC address of the bridge to this interface
                   primary: true
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/net-config-linux-bridge.yaml b/net-config-linux-bridge.yaml
index 0980803e99..d8274f3c02 100644
--- a/net-config-linux-bridge.yaml
+++ b/net-config-linux-bridge.yaml
@@ -1,8 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
   Software Config to drive os-net-config for a simple bridge.
-
 parameters:
   ControlPlaneIp:
     default: ''
@@ -35,43 +33,45 @@ parameters:
   ControlPlaneDefaultRoute: # Override this via parameter_defaults
     description: The default route of the control plane network.
     type: string
-    default: '192.0.2.1'
+    default: 192.0.2.1
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-    default: '169.254.169.254/32'
-
-
+    default: 169.254.169.254/32
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: linux_bridge
-              name: {get_input: bridge_name}
-              addresses:
-                -
-                  ip_netmask: {get_param: ControlPlaneIp}
-              members:
-                -
-                  type: interface
-                  name: {get_input: interface_name}
+        str_replace:
+          template:
+            get_file: network/scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: linux_bridge
+                name: bridge_name
+                addresses:
+                - ip_netmask:
+                    get_param: ControlPlaneIp
+                members:
+                - type: interface
+                  name: interface_name
                   # force the MAC address of the bridge to this interface
                   primary: true
-              routes:
-                -
-                  ip_netmask: 0.0.0.0/0
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
+                routes:
+                - ip_netmask: 0.0.0.0/0
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
                   default: true
-                -
-                  ip_netmask: {get_param: EC2MetadataIp}
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-
+                - ip_netmask:
+                    get_param: EC2MetadataIp
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/net-config-static-bridge-with-external-dhcp.yaml b/net-config-static-bridge-with-external-dhcp.yaml
index 3ea4e6abf7..a1d86728da 100644
--- a/net-config-static-bridge-with-external-dhcp.yaml
+++ b/net-config-static-bridge-with-external-dhcp.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config for a simple bridge configured
-  with a static IP address for the ctlplane network.
-
+  Software Config to drive os-net-config for a simple bridge configured with a static IP address for the ctlplane network.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -47,44 +44,44 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: ovs_bridge
-              name: {get_input: bridge_name}
-              use_dhcp: true
-              members:
-                -
-                  type: interface
-                  name: {get_input: interface_name}
+        str_replace:
+          template:
+            get_file: network/scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: ovs_bridge
+                name: bridge_name
+                use_dhcp: true
+                members:
+                - type: interface
+                  name: interface_name
                   # force the MAC address of the bridge to this interface
                   primary: true
-            -
-              type: interface
-              name: br-ex:0
-              addresses:
-                -
-                  ip_netmask:
+              - type: interface
+                name: br-ex:0
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/net-config-static-bridge.yaml b/net-config-static-bridge.yaml
index a3d6d8b55f..1e1498b30d 100644
--- a/net-config-static-bridge.yaml
+++ b/net-config-static-bridge.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config for a simple bridge configured
-  with a static IP address for the ctlplane network.
-
+  Software Config to drive os-net-config for a simple bridge configured with a static IP address for the ctlplane network.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -47,42 +44,44 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: ovs_bridge
-              name: {get_input: bridge_name}
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: network/scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: ovs_bridge
+                name: bridge_name
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-              members:
-                -
-                  type: interface
-                  name: {get_input: interface_name}
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+                members:
+                - type: interface
+                  name: interface_name
                   # force the MAC address of the bridge to this interface
                   primary: true
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/net-config-static.yaml b/net-config-static.yaml
index 9de16cd83e..c67b4e9942 100644
--- a/net-config-static.yaml
+++ b/net-config-static.yaml
@@ -1,8 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
   Software Config to drive os-net-config for a simple bridge.
-
 parameters:
   ControlPlaneIp:
     default: ''
@@ -46,37 +44,39 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: interface
-              name: {get_input: interface_name}
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: network/scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: interface
+                name: interface_name
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/bond-with-vlans/ceph-storage.yaml b/network/config/bond-with-vlans/ceph-storage.yaml
index 9f537c0255..2f92f4b52e 100644
--- a/network/config/bond-with-vlans/ceph-storage.yaml
+++ b/network/config/bond-with-vlans/ceph-storage.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config with 2 bonded nics on a bridge
-  with VLANs attached for the ceph storage role.
-
+  Software Config to drive os-net-config with 2 bonded nics on a bridge with VLANs attached for the ceph storage role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -35,14 +32,16 @@ parameters:
     type: string
   BondInterfaceOvsOptions:
     default: ''
-    description: The ovs_options string for the bond interface. Set things like
-                 lacp=active and/or bond_mode=balance-slb using this option.
+    description: The ovs_options string for the bond interface. Set things like lacp=active and/or bond_mode=balance-slb using
+      this option.
     type: string
     constraints:
-      - allowed_pattern: "^((?!balance.tcp).)*$"
-        description: |
-          The balance-tcp bond mode is known to cause packet loss and
-          should not be used in BondInterfaceOvsOptions.
+    - allowed_pattern: ^((?!balance.tcp).)*$
+      description: 'The balance-tcp bond mode is known to cause packet loss and
+
+        should not be used in BondInterfaceOvsOptions.
+
+        '
   ExternalNetworkVlanID:
     default: 10
     description: Vlan ID for the external network traffic.
@@ -75,7 +74,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -89,64 +88,63 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: interface
-              name: nic1
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: interface
+                name: nic1
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-            -
-              type: ovs_bridge
-              name: br-bond
-              members:
-                -
-                  type: ovs_bond
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+              - type: ovs_bridge
+                name: br-bond
+                members:
+                - type: ovs_bond
                   name: bond1
-                  ovs_options: {get_param: BondInterfaceOvsOptions}
+                  ovs_options:
+                    get_param: BondInterfaceOvsOptions
                   members:
-                    -
-                      type: interface
-                      name: nic2
-                      primary: true
-                    -
-                      type: interface
-                      name: nic3
-                -
-                  type: vlan
+                  - type: interface
+                    name: nic2
+                    primary: true
+                  - type: interface
+                    name: nic3
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: StorageNetworkVlanID}
+                  vlan_id:
+                    get_param: StorageNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: StorageIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: StorageMgmtNetworkVlanID}
+                  vlan_id:
+                    get_param: StorageMgmtNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageMgmtIpSubnet}
+                  - ip_netmask:
+                      get_param: StorageMgmtIpSubnet
                 # Uncomment when including environments/network-management.yaml
                 # If setting default route on the Management interface, comment
                 # out the default route on the Control Plane.
@@ -161,8 +159,9 @@ resources:
                 #    -
                 #      default: true
                 #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/bond-with-vlans/cinder-storage.yaml b/network/config/bond-with-vlans/cinder-storage.yaml
index b4d71fa3bc..0e53e20231 100644
--- a/network/config/bond-with-vlans/cinder-storage.yaml
+++ b/network/config/bond-with-vlans/cinder-storage.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config with 2 bonded nics on a bridge
-  with VLANs attached for the cinder storage role.
-
+  Software Config to drive os-net-config with 2 bonded nics on a bridge with VLANs attached for the cinder storage role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -35,14 +32,16 @@ parameters:
     type: string
   BondInterfaceOvsOptions:
     default: ''
-    description: The ovs_options string for the bond interface. Set things like
-                 lacp=active and/or bond_mode=balance-slb using this option.
+    description: The ovs_options string for the bond interface. Set things like lacp=active and/or bond_mode=balance-slb using
+      this option.
     type: string
     constraints:
-      - allowed_pattern: "^((?!balance.tcp).)*$"
-        description: |
-          The balance-tcp bond mode is known to cause packet loss and
-          should not be used in BondInterfaceOvsOptions.
+    - allowed_pattern: ^((?!balance.tcp).)*$
+      description: 'The balance-tcp bond mode is known to cause packet loss and
+
+        should not be used in BondInterfaceOvsOptions.
+
+        '
   ExternalNetworkVlanID:
     default: 10
     description: Vlan ID for the external network traffic.
@@ -75,7 +74,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -89,71 +88,70 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: interface
-              name: nic1
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: interface
+                name: nic1
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-            -
-              type: ovs_bridge
-              name: br-bond
-              members:
-                -
-                  type: ovs_bond
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+              - type: ovs_bridge
+                name: br-bond
+                members:
+                - type: ovs_bond
                   name: bond1
-                  ovs_options: {get_param: BondInterfaceOvsOptions}
+                  ovs_options:
+                    get_param: BondInterfaceOvsOptions
                   members:
-                    -
-                      type: interface
-                      name: nic2
-                      primary: true
-                    -
-                      type: interface
-                      name: nic3
-                -
-                  type: vlan
+                  - type: interface
+                    name: nic2
+                    primary: true
+                  - type: interface
+                    name: nic3
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: InternalApiNetworkVlanID}
+                  vlan_id:
+                    get_param: InternalApiNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: InternalApiIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: InternalApiIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: StorageNetworkVlanID}
+                  vlan_id:
+                    get_param: StorageNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: StorageIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: StorageMgmtNetworkVlanID}
+                  vlan_id:
+                    get_param: StorageMgmtNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageMgmtIpSubnet}
+                  - ip_netmask:
+                      get_param: StorageMgmtIpSubnet
                 # Uncomment when including environments/network-management.yaml
                 # If setting default route on the Management interface, comment
                 # out the default route on the Control Plane.
@@ -168,8 +166,9 @@ resources:
                 #    -
                 #      default: true
                 #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/bond-with-vlans/compute-dpdk.yaml b/network/config/bond-with-vlans/compute-dpdk.yaml
index 3fc764bef9..a9b314a492 100644
--- a/network/config/bond-with-vlans/compute-dpdk.yaml
+++ b/network/config/bond-with-vlans/compute-dpdk.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config with 2 bonded nics on a bridge
-  with VLANs attached for the compute role.
-
+  Software Config to drive os-net-config with 2 bonded nics on a bridge with VLANs attached for the compute role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -35,8 +32,8 @@ parameters:
     type: string
   BondInterfaceOvsOptions:
     default: ''
-    description: The ovs_options string for the bond interface. Set things like
-                 lacp=active and/or bond_mode=balance-slb using this option.
+    description: The ovs_options string for the bond interface. Set things like lacp=active and/or bond_mode=balance-slb using
+      this option.
     type: string
   ExternalNetworkVlanID:
     default: 10
@@ -70,7 +67,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -84,71 +81,70 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: interface
-              name: nic1
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: interface
+                name: nic1
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-            -
-              type: ovs_bridge
-              name: {get_input: bridge_name}
-              members:
-                -
-                  type: ovs_bond
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+              - type: ovs_bridge
+                name: bridge_name
+                members:
+                - type: ovs_bond
                   name: bond1
-                  ovs_options: {get_param: BondInterfaceOvsOptions}
+                  ovs_options:
+                    get_param: BondInterfaceOvsOptions
                   members:
-                    -
-                      type: interface
-                      name: nic2
-                      primary: true
-                    -
-                      type: interface
-                      name: nic3
-                -
-                  type: vlan
+                  - type: interface
+                    name: nic2
+                    primary: true
+                  - type: interface
+                    name: nic3
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: InternalApiNetworkVlanID}
+                  vlan_id:
+                    get_param: InternalApiNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: InternalApiIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: InternalApiIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: StorageNetworkVlanID}
+                  vlan_id:
+                    get_param: StorageNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: StorageIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: TenantNetworkVlanID}
+                  vlan_id:
+                    get_param: TenantNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: TenantIpSubnet}
+                  - ip_netmask:
+                      get_param: TenantIpSubnet
                 # Uncomment when including environments/network-management.yaml
                 # If setting default route on the Management interface, comment
                 # out the default route on the Control Plane.
@@ -163,30 +159,25 @@ resources:
                 #    -
                 #      default: true
                 #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-            -
-              type: ovs_user_bridge
-              name: br-link
-              members:
-                -
-                  type: ovs_dpdk_bond
+              - type: ovs_user_bridge
+                name: br-link
+                members:
+                - type: ovs_dpdk_bond
                   name: dpdkbond0
                   members:
-                    -
-                      type: ovs_dpdk_port
-                      name: dpdk0
-                      members:
-                        -
-                          type: interface
-                          name: nic4
-                    -
-                      type: ovs_dpdk_port
-                      name: dpdk1
-                      members:
-                        -
-                          type: interface
-                          name: nic5
-
+                  - type: ovs_dpdk_port
+                    name: dpdk0
+                    members:
+                    - type: interface
+                      name: nic4
+                  - type: ovs_dpdk_port
+                    name: dpdk1
+                    members:
+                    - type: interface
+                      name: nic5
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/bond-with-vlans/compute.yaml b/network/config/bond-with-vlans/compute.yaml
index b2cfb0a25c..4cac448b69 100644
--- a/network/config/bond-with-vlans/compute.yaml
+++ b/network/config/bond-with-vlans/compute.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config with 2 bonded nics on a bridge
-  with VLANs attached for the compute role.
-
+  Software Config to drive os-net-config with 2 bonded nics on a bridge with VLANs attached for the compute role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -35,14 +32,16 @@ parameters:
     type: string
   BondInterfaceOvsOptions:
     default: ''
-    description: The ovs_options string for the bond interface. Set things like
-                 lacp=active and/or bond_mode=balance-slb using this option.
+    description: The ovs_options string for the bond interface. Set things like lacp=active and/or bond_mode=balance-slb using
+      this option.
     type: string
     constraints:
-      - allowed_pattern: "^((?!balance.tcp).)*$"
-        description: |
-          The balance-tcp bond mode is known to cause packet loss and
-          should not be used in BondInterfaceOvsOptions.
+    - allowed_pattern: ^((?!balance.tcp).)*$
+      description: 'The balance-tcp bond mode is known to cause packet loss and
+
+        should not be used in BondInterfaceOvsOptions.
+
+        '
   ExternalNetworkVlanID:
     default: 10
     description: Vlan ID for the external network traffic.
@@ -75,7 +74,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -89,71 +88,70 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: interface
-              name: nic1
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: interface
+                name: nic1
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-            -
-              type: ovs_bridge
-              name: {get_input: bridge_name}
-              members:
-                -
-                  type: ovs_bond
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+              - type: ovs_bridge
+                name: bridge_name
+                members:
+                - type: ovs_bond
                   name: bond1
-                  ovs_options: {get_param: BondInterfaceOvsOptions}
+                  ovs_options:
+                    get_param: BondInterfaceOvsOptions
                   members:
-                    -
-                      type: interface
-                      name: nic2
-                      primary: true
-                    -
-                      type: interface
-                      name: nic3
-                -
-                  type: vlan
+                  - type: interface
+                    name: nic2
+                    primary: true
+                  - type: interface
+                    name: nic3
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: InternalApiNetworkVlanID}
+                  vlan_id:
+                    get_param: InternalApiNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: InternalApiIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: InternalApiIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: StorageNetworkVlanID}
+                  vlan_id:
+                    get_param: StorageNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: StorageIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: TenantNetworkVlanID}
+                  vlan_id:
+                    get_param: TenantNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: TenantIpSubnet}
+                  - ip_netmask:
+                      get_param: TenantIpSubnet
                 # Uncomment when including environments/network-management.yaml
                 # If setting default route on the Management interface, comment
                 # out the default route on the Control Plane.
@@ -168,8 +166,9 @@ resources:
                 #    -
                 #      default: true
                 #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/bond-with-vlans/controller-no-external.yaml b/network/config/bond-with-vlans/controller-no-external.yaml
index 4c3e59fa65..460909743d 100644
--- a/network/config/bond-with-vlans/controller-no-external.yaml
+++ b/network/config/bond-with-vlans/controller-no-external.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config with 2 bonded nics on a bridge
-  with VLANs attached for the controller role.
-
+  Software Config to drive os-net-config with 2 bonded nics on a bridge with VLANs attached for the controller role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -35,14 +32,16 @@ parameters:
     type: string
   BondInterfaceOvsOptions:
     default: ''
-    description: The ovs_options string for the bond interface. Set things like
-                 lacp=active and/or bond_mode=balance-slb using this option.
+    description: The ovs_options string for the bond interface. Set things like lacp=active and/or bond_mode=balance-slb using
+      this option.
     type: string
     constraints:
-      - allowed_pattern: "^((?!balance.tcp).)*$"
-        description: |
-          The balance-tcp bond mode is known to cause packet loss and
-          should not be used in BondInterfaceOvsOptions.
+    - allowed_pattern: ^((?!balance.tcp).)*$
+      description: 'The balance-tcp bond mode is known to cause packet loss and
+
+        should not be used in BondInterfaceOvsOptions.
+
+        '
   ExternalNetworkVlanID:
     default: 10
     description: Vlan ID for the external network traffic.
@@ -71,7 +70,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute:
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: default route for the external network
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -89,79 +88,76 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: interface
-              name: nic1
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: interface
+                name: nic1
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-            -
-              type: ovs_bridge
-              name: {get_input: bridge_name}
-              use_dhcp: true
-              members:
-                -
-                  type: ovs_bond
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+              - type: ovs_bridge
+                name: bridge_name
+                use_dhcp: true
+                members:
+                - type: ovs_bond
                   name: bond1
-                  ovs_options: {get_param: BondInterfaceOvsOptions}
+                  ovs_options:
+                    get_param: BondInterfaceOvsOptions
                   members:
-                    -
-                      type: interface
-                      name: nic2
-                      primary: true
-                    -
-                      type: interface
-                      name: nic3
-                -
-                  type: vlan
+                  - type: interface
+                    name: nic2
+                    primary: true
+                  - type: interface
+                    name: nic3
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: InternalApiNetworkVlanID}
+                  vlan_id:
+                    get_param: InternalApiNetworkVlanID
                   addresses:
-                  -
-                    ip_netmask: {get_param: InternalApiIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: InternalApiIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: StorageNetworkVlanID}
+                  vlan_id:
+                    get_param: StorageNetworkVlanID
                   addresses:
-                  -
-                    ip_netmask: {get_param: StorageIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: StorageIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: StorageMgmtNetworkVlanID}
+                  vlan_id:
+                    get_param: StorageMgmtNetworkVlanID
                   addresses:
-                  -
-                    ip_netmask: {get_param: StorageMgmtIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: StorageMgmtIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: TenantNetworkVlanID}
+                  vlan_id:
+                    get_param: TenantNetworkVlanID
                   addresses:
-                  -
-                    ip_netmask: {get_param: TenantIpSubnet}
+                  - ip_netmask:
+                      get_param: TenantIpSubnet
                 # Uncomment when including environments/network-management.yaml
                 # If setting default route on the Management interface, comment
                 # out the default route on the Control Plane.
@@ -176,8 +172,9 @@ resources:
                 #    -
                 #      default: true
                 #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/bond-with-vlans/controller-v6.yaml b/network/config/bond-with-vlans/controller-v6.yaml
index d45ab33c24..d07a26ff6a 100644
--- a/network/config/bond-with-vlans/controller-v6.yaml
+++ b/network/config/bond-with-vlans/controller-v6.yaml
@@ -1,11 +1,8 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config with 2 bonded nics on a bridge
-  with VLANs attached for the controller role with IPv6 on the External
-  network. The IPv6 default route is on the External network, and the
-  IPv4 default route is on the Control Plane.
-
+  Software Config to drive os-net-config with 2 bonded nics on a bridge with VLANs attached for the controller role with IPv6
+  on the External network. The IPv6 default route is on the External network, and the IPv4 default route is on the Control
+  Plane.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -36,15 +33,17 @@ parameters:
     description: IP address/subnet on the management network
     type: string
   BondInterfaceOvsOptions:
-    default: 'bond_mode=active-backup'
-    description: The ovs_options string for the bond interface. Set things like
-                 lacp=active and/or bond_mode=balance-slb using this option.
+    default: bond_mode=active-backup
+    description: The ovs_options string for the bond interface. Set things like lacp=active and/or bond_mode=balance-slb using
+      this option.
     type: string
     constraints:
-      - allowed_pattern: "^((?!balance.tcp).)*$"
-        description: |
-          The balance-tcp bond mode is known to cause packet loss and
-          should not be used in BondInterfaceOvsOptions.
+    - allowed_pattern: ^((?!balance.tcp).)*$
+      description: 'The balance-tcp bond mode is known to cause packet loss and
+
+        should not be used in BondInterfaceOvsOptions.
+
+        '
   ExternalNetworkVlanID:
     default: 10
     description: Vlan ID for the external network traffic.
@@ -77,7 +76,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute:
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: default route for the external network
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -91,89 +90,88 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: interface
-              name: nic1
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: interface
+                name: nic1
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-            -
-              type: ovs_bridge
-              name: {get_input: bridge_name}
-              dns_servers: {get_param: DnsServers}
-              members:
-                -
-                  type: ovs_bond
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+              - type: ovs_bridge
+                name: bridge_name
+                dns_servers:
+                  get_param: DnsServers
+                members:
+                - type: ovs_bond
                   name: bond1
-                  ovs_options: {get_param: BondInterfaceOvsOptions}
+                  ovs_options:
+                    get_param: BondInterfaceOvsOptions
                   members:
-                    -
-                      type: interface
-                      name: nic2
-                      primary: true
-                    -
-                      type: interface
-                      name: nic3
-                -
-                  type: vlan
+                  - type: interface
+                    name: nic2
+                    primary: true
+                  - type: interface
+                    name: nic3
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: ExternalNetworkVlanID}
+                  vlan_id:
+                    get_param: ExternalNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: ExternalIpSubnet}
+                  - ip_netmask:
+                      get_param: ExternalIpSubnet
                   routes:
-                    -
-                      default: true
-                      next_hop: {get_param: ExternalInterfaceDefaultRoute}
-                -
-                  type: vlan
+                  - default: true
+                    next_hop:
+                      get_param: ExternalInterfaceDefaultRoute
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: InternalApiNetworkVlanID}
+                  vlan_id:
+                    get_param: InternalApiNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: InternalApiIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: InternalApiIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: StorageNetworkVlanID}
+                  vlan_id:
+                    get_param: StorageNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: StorageIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: StorageMgmtNetworkVlanID}
+                  vlan_id:
+                    get_param: StorageMgmtNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageMgmtIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: StorageMgmtIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: TenantNetworkVlanID}
+                  vlan_id:
+                    get_param: TenantNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: TenantIpSubnet}
+                  - ip_netmask:
+                      get_param: TenantIpSubnet
                 # Uncomment when including environments/network-management.yaml
                 # If setting default route on the Management interface, comment
                 # out the default route on the External interface. This will
@@ -189,8 +187,9 @@ resources:
                 #    -
                 #      default: true
                 #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/bond-with-vlans/controller.yaml b/network/config/bond-with-vlans/controller.yaml
index 677c90c557..e2973a72d2 100644
--- a/network/config/bond-with-vlans/controller.yaml
+++ b/network/config/bond-with-vlans/controller.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config with 2 bonded nics on a bridge
-  with VLANs attached for the controller role.
-
+  Software Config to drive os-net-config with 2 bonded nics on a bridge with VLANs attached for the controller role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -34,15 +31,17 @@ parameters:
     description: IP address/subnet on the management network
     type: string
   BondInterfaceOvsOptions:
-    default: 'bond_mode=active-backup'
-    description: The ovs_options string for the bond interface. Set things like
-                 lacp=active and/or bond_mode=balance-slb using this option.
+    default: bond_mode=active-backup
+    description: The ovs_options string for the bond interface. Set things like lacp=active and/or bond_mode=balance-slb using
+      this option.
     type: string
     constraints:
-      - allowed_pattern: "^((?!balance.tcp).)*$"
-        description: |
-          The balance-tcp bond mode is known to cause packet loss and
-          should not be used in BondInterfaceOvsOptions.
+    - allowed_pattern: ^((?!balance.tcp).)*$
+      description: 'The balance-tcp bond mode is known to cause packet loss and
+
+        should not be used in BondInterfaceOvsOptions.
+
+        '
   ExternalNetworkVlanID:
     default: 10
     description: Vlan ID for the external network traffic.
@@ -71,7 +70,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute:
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: default route for the external network
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -89,86 +88,85 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: interface
-              name: nic1
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: interface
+                name: nic1
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-            -
-              type: ovs_bridge
-              name: {get_input: bridge_name}
-              dns_servers: {get_param: DnsServers}
-              members:
-                -
-                  type: ovs_bond
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+              - type: ovs_bridge
+                name: bridge_name
+                dns_servers:
+                  get_param: DnsServers
+                members:
+                - type: ovs_bond
                   name: bond1
-                  ovs_options: {get_param: BondInterfaceOvsOptions}
+                  ovs_options:
+                    get_param: BondInterfaceOvsOptions
                   members:
-                    -
-                      type: interface
-                      name: nic2
-                      primary: true
-                    -
-                      type: interface
-                      name: nic3
-                -
-                  type: vlan
+                  - type: interface
+                    name: nic2
+                    primary: true
+                  - type: interface
+                    name: nic3
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: ExternalNetworkVlanID}
+                  vlan_id:
+                    get_param: ExternalNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: ExternalIpSubnet}
+                  - ip_netmask:
+                      get_param: ExternalIpSubnet
                   routes:
-                    -
-                      default: true
-                      next_hop: {get_param: ExternalInterfaceDefaultRoute}
-                -
-                  type: vlan
+                  - default: true
+                    next_hop:
+                      get_param: ExternalInterfaceDefaultRoute
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: InternalApiNetworkVlanID}
+                  vlan_id:
+                    get_param: InternalApiNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: InternalApiIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: InternalApiIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: StorageNetworkVlanID}
+                  vlan_id:
+                    get_param: StorageNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: StorageIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: StorageMgmtNetworkVlanID}
+                  vlan_id:
+                    get_param: StorageMgmtNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageMgmtIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: StorageMgmtIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: TenantNetworkVlanID}
+                  vlan_id:
+                    get_param: TenantNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: TenantIpSubnet}
+                  - ip_netmask:
+                      get_param: TenantIpSubnet
                 # Uncomment when including environments/network-management.yaml
                 # If setting default route on the Management interface, comment
                 # out the default route on the External interface. This will
@@ -184,8 +182,9 @@ resources:
                 #    -
                 #      default: true
                 #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/bond-with-vlans/swift-storage.yaml b/network/config/bond-with-vlans/swift-storage.yaml
index e16d6b6e7d..5bdba80298 100644
--- a/network/config/bond-with-vlans/swift-storage.yaml
+++ b/network/config/bond-with-vlans/swift-storage.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config with 2 bonded nics on a bridge
-  with VLANs attached for the swift storage role.
-
+  Software Config to drive os-net-config with 2 bonded nics on a bridge with VLANs attached for the swift storage role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -35,14 +32,16 @@ parameters:
     type: string
   BondInterfaceOvsOptions:
     default: ''
-    description: The ovs_options string for the bond interface. Set things like
-                 lacp=active and/or bond_mode=balance-slb using this option.
+    description: The ovs_options string for the bond interface. Set things like lacp=active and/or bond_mode=balance-slb using
+      this option.
     type: string
     constraints:
-      - allowed_pattern: "^((?!balance.tcp).)*$"
-        description: |
-          The balance-tcp bond mode is known to cause packet loss and
-          should not be used in BondInterfaceOvsOptions.
+    - allowed_pattern: ^((?!balance.tcp).)*$
+      description: 'The balance-tcp bond mode is known to cause packet loss and
+
+        should not be used in BondInterfaceOvsOptions.
+
+        '
   ExternalNetworkVlanID:
     default: 10
     description: Vlan ID for the external network traffic.
@@ -75,7 +74,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -89,71 +88,70 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: interface
-              name: nic1
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: interface
+                name: nic1
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-            -
-              type: ovs_bridge
-              name: br-bond
-              members:
-                -
-                  type: ovs_bond
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+              - type: ovs_bridge
+                name: br-bond
+                members:
+                - type: ovs_bond
                   name: bond1
-                  ovs_options: {get_param: BondInterfaceOvsOptions}
+                  ovs_options:
+                    get_param: BondInterfaceOvsOptions
                   members:
-                    -
-                      type: interface
-                      name: nic2
-                      primary: true
-                    -
-                      type: interface
-                      name: nic3
-                -
-                  type: vlan
+                  - type: interface
+                    name: nic2
+                    primary: true
+                  - type: interface
+                    name: nic3
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: InternalApiNetworkVlanID}
+                  vlan_id:
+                    get_param: InternalApiNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: InternalApiIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: InternalApiIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: StorageNetworkVlanID}
+                  vlan_id:
+                    get_param: StorageNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageIpSubnet}
-                -
-                  type: vlan
+                  - ip_netmask:
+                      get_param: StorageIpSubnet
+                - type: vlan
                   device: bond1
-                  vlan_id: {get_param: StorageMgmtNetworkVlanID}
+                  vlan_id:
+                    get_param: StorageMgmtNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageMgmtIpSubnet}
+                  - ip_netmask:
+                      get_param: StorageMgmtIpSubnet
                 # Uncomment when including environments/network-management.yaml
                 # If setting default route on the Management interface, comment
                 # out the default route on the Control Plane.
@@ -168,8 +166,9 @@ resources:
                 #    -
                 #      default: true
                 #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/multiple-nics/ceph-storage.yaml b/network/config/multiple-nics/ceph-storage.yaml
index c31c6e65c9..e9c3421372 100644
--- a/network/config/multiple-nics/ceph-storage.yaml
+++ b/network/config/multiple-nics/ceph-storage.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure multiple interfaces
-  for the ceph storage role.
-
+  Software Config to drive os-net-config to configure multiple interfaces for the ceph storage role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -65,7 +62,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -79,48 +76,48 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: interface
-              name: nic1
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: interface
+                name: nic1
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-            -
-              type: interface
-              name: nic2
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageIpSubnet}
-            -
-              type: interface
-              name: nic3
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageMgmtIpSubnet}
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+              - type: interface
+                name: nic2
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: StorageIpSubnet
+              - type: interface
+                name: nic3
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: StorageMgmtIpSubnet
             # Uncomment when including environments/network-management.yaml
             # If setting default route on the Management interface, comment
             # out the default route on the Control Plane.
@@ -135,8 +132,9 @@ resources:
             #    -
             #      default: true
             #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/multiple-nics/cinder-storage.yaml b/network/config/multiple-nics/cinder-storage.yaml
index 4f8b7f6486..f58f1168f1 100644
--- a/network/config/multiple-nics/cinder-storage.yaml
+++ b/network/config/multiple-nics/cinder-storage.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure multiple interfaces
-  for the cinder storage role.
-
+  Software Config to drive os-net-config to configure multiple interfaces for the cinder storage role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -65,7 +62,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -79,55 +76,54 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: interface
-              name: nic1
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: interface
+                name: nic1
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-            -
-              type: interface
-              name: nic2
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageIpSubnet}
-            -
-              type: interface
-              name: nic3
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageMgmtIpSubnet}
-            -
-              type: interface
-              name: nic4
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: InternalApiIpSubnet}
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+              - type: interface
+                name: nic2
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: StorageIpSubnet
+              - type: interface
+                name: nic3
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: StorageMgmtIpSubnet
+              - type: interface
+                name: nic4
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: InternalApiIpSubnet
             # Uncomment when including environments/network-management.yaml
             # If setting default route on the Management interface, comment
             # out the default route on the Control Plane.
@@ -142,8 +138,9 @@ resources:
             #    -
             #      default: true
             #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/multiple-nics/compute.yaml b/network/config/multiple-nics/compute.yaml
index 2e07d45e06..9b0c8c02a9 100644
--- a/network/config/multiple-nics/compute.yaml
+++ b/network/config/multiple-nics/compute.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure multiple interfaces
-  for the compute role.
-
+  Software Config to drive os-net-config to configure multiple interfaces for the compute role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -65,7 +62,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -79,58 +76,56 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: interface
-              name: nic1
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: interface
+                name: nic1
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-            -
-              type: interface
-              name: nic2
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageIpSubnet}
-            -
-              type: interface
-              name: nic4
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: InternalApiIpSubnet}
-            -
-              type: ovs_bridge
-              name: br-tenant
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: TenantIpSubnet}
-              members:
-                -
-                  type: interface
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+              - type: interface
+                name: nic2
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: StorageIpSubnet
+              - type: interface
+                name: nic4
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: InternalApiIpSubnet
+              - type: ovs_bridge
+                name: br-tenant
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: TenantIpSubnet
+                members:
+                - type: interface
                   name: nic5
                   use_dhcp: false
                   primary: true
@@ -148,8 +143,9 @@ resources:
             #    -
             #      default: true
             #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/multiple-nics/controller-v6.yaml b/network/config/multiple-nics/controller-v6.yaml
index bbc89ab6f7..a0ed9f7827 100644
--- a/network/config/multiple-nics/controller-v6.yaml
+++ b/network/config/multiple-nics/controller-v6.yaml
@@ -1,11 +1,7 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure multiple interfaces
-  for the controller role with IPv6 on the External network. The IPv6
-  default route is on the External network, and the IPv4 default route
-  is on the Control Plane.
-
+  Software Config to drive os-net-config to configure multiple interfaces for the controller role with IPv6 on the External
+  network. The IPv6 default route is on the External network, and the IPv4 default route is on the Control Plane.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -67,7 +63,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute:
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: default route for the external network
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -81,84 +77,80 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: interface
-              name: nic1
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: interface
+                name: nic1
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
                 # IPv4 Default Route
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-            -
-              type: interface
-              name: nic2
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageIpSubnet}
-            -
-              type: interface
-              name: nic3
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageMgmtIpSubnet}
-            -
-              type: interface
-              name: nic4
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: InternalApiIpSubnet}
-            -
-              type: ovs_bridge
-              name: br-tenant
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: TenantIpSubnet}
-              members:
-                -
-                  type: interface
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+              - type: interface
+                name: nic2
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: StorageIpSubnet
+              - type: interface
+                name: nic3
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: StorageMgmtIpSubnet
+              - type: interface
+                name: nic4
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: InternalApiIpSubnet
+              - type: ovs_bridge
+                name: br-tenant
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: TenantIpSubnet
+                members:
+                - type: interface
                   name: nic5
                   use_dhcp: false
                   primary: true
-            -
-              type: ovs_bridge
-              name: {get_input: bridge_name}
-              dns_servers: {get_param: DnsServers}
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: ExternalIpSubnet}
-              routes:
-                -
-                  default: true
-                  next_hop: {get_param: ExternalInterfaceDefaultRoute}
-              members:
-                -
-                  type: interface
+              - type: ovs_bridge
+                name: bridge_name
+                dns_servers:
+                  get_param: DnsServers
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: ExternalIpSubnet
+                routes:
+                - default: true
+                  next_hop:
+                    get_param: ExternalInterfaceDefaultRoute
+                members:
+                - type: interface
                   name: nic6
                   primary: true
             # Uncomment when including environments/network-management.yaml
@@ -176,8 +168,9 @@ resources:
             #    -
             #      default: true
             #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/multiple-nics/controller.yaml b/network/config/multiple-nics/controller.yaml
index a0176b5be0..e38c545c7e 100644
--- a/network/config/multiple-nics/controller.yaml
+++ b/network/config/multiple-nics/controller.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure multiple interfaces
-  for the controller role.
-
+  Software Config to drive os-net-config to configure multiple interfaces for the controller role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -65,7 +62,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute:
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: default route for the external network
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -79,80 +76,76 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: interface
-              name: nic1
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: interface
+                name: nic1
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-            -
-              type: interface
-              name: nic2
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageIpSubnet}
-            -
-              type: interface
-              name: nic3
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageMgmtIpSubnet}
-            -
-              type: interface
-              name: nic4
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: InternalApiIpSubnet}
-            -
-              type: ovs_bridge
-              name: br-tenant
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: TenantIpSubnet}
-              members:
-                -
-                  type: interface
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+              - type: interface
+                name: nic2
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: StorageIpSubnet
+              - type: interface
+                name: nic3
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: StorageMgmtIpSubnet
+              - type: interface
+                name: nic4
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: InternalApiIpSubnet
+              - type: ovs_bridge
+                name: br-tenant
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: TenantIpSubnet
+                members:
+                - type: interface
                   name: nic5
                   use_dhcp: false
                   primary: true
-            -
-              type: ovs_bridge
-              name: {get_input: bridge_name}
-              dns_servers: {get_param: DnsServers}
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: ExternalIpSubnet}
-              routes:
-                -
-                  default: true
-                  next_hop: {get_param: ExternalInterfaceDefaultRoute}
-              members:
-                -
-                  type: interface
+              - type: ovs_bridge
+                name: bridge_name
+                dns_servers:
+                  get_param: DnsServers
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: ExternalIpSubnet
+                routes:
+                - default: true
+                  next_hop:
+                    get_param: ExternalInterfaceDefaultRoute
+                members:
+                - type: interface
                   name: nic6
                   primary: true
             # Uncomment when including environments/network-management.yaml
@@ -170,8 +163,9 @@ resources:
             #    -
             #      default: true
             #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/multiple-nics/swift-storage.yaml b/network/config/multiple-nics/swift-storage.yaml
index 0508310595..1ad503a7b3 100644
--- a/network/config/multiple-nics/swift-storage.yaml
+++ b/network/config/multiple-nics/swift-storage.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure multiple interfaces
-  for the swift storage role.
-
+  Software Config to drive os-net-config to configure multiple interfaces for the swift storage role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -65,7 +62,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -79,55 +76,54 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: interface
-              name: nic1
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: interface
+                name: nic1
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-            -
-              type: interface
-              name: nic2
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageIpSubnet}
-            -
-              type: interface
-              name: nic3
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageMgmtIpSubnet}
-            -
-              type: interface
-              name: nic4
-              use_dhcp: false
-              addresses:
-                -
-                  ip_netmask: {get_param: InternalApiIpSubnet}
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+              - type: interface
+                name: nic2
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: StorageIpSubnet
+              - type: interface
+                name: nic3
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: StorageMgmtIpSubnet
+              - type: interface
+                name: nic4
+                use_dhcp: false
+                addresses:
+                - ip_netmask:
+                    get_param: InternalApiIpSubnet
             # Uncomment when including environments/network-management.yaml
             # If setting default route on the Management interface, comment
             # out the default route on the Control Plane.
@@ -142,8 +138,9 @@ resources:
             #    -
             #      default: true
             #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/single-nic-linux-bridge-vlans/ceph-storage.yaml b/network/config/single-nic-linux-bridge-vlans/ceph-storage.yaml
index fc8e8b6f69..0a6faa795b 100644
--- a/network/config/single-nic-linux-bridge-vlans/ceph-storage.yaml
+++ b/network/config/single-nic-linux-bridge-vlans/ceph-storage.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure VLANs for the
-  ceph storage role.
-
+  Software Config to drive os-net-config to configure VLANs for the ceph storage role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -65,7 +62,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -79,54 +76,55 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: linux_bridge
-              name: br-storage
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: linux_bridge
+                name: br-storage
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-              members:
-                -
-                  type: interface
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+                members:
+                - type: interface
                   name: nic1
                   # force the MAC address of the bridge to this interface
                   primary: true
-            -
-              type: vlan
-              vlan_id: {get_param: StorageNetworkVlanID}
-              device: br-storage
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageIpSubnet}
-            -
-              type: vlan
-              vlan_id: {get_param: StorageMgmtNetworkVlanID}
-              device: br-storage
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageMgmtIpSubnet}
+              - type: vlan
+                vlan_id:
+                  get_param: StorageNetworkVlanID
+                device: br-storage
+                addresses:
+                - ip_netmask:
+                    get_param: StorageIpSubnet
+              - type: vlan
+                vlan_id:
+                  get_param: StorageMgmtNetworkVlanID
+                device: br-storage
+                addresses:
+                - ip_netmask:
+                    get_param: StorageMgmtIpSubnet
               # Uncomment when including environments/network-management.yaml
               # If setting default route on the Management interface, comment
               # out the default route on the Control Plane.
@@ -141,8 +139,9 @@ resources:
               #    -
               #      default: true
               #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/single-nic-linux-bridge-vlans/cinder-storage.yaml b/network/config/single-nic-linux-bridge-vlans/cinder-storage.yaml
index 6fb247edf4..5abaea6636 100644
--- a/network/config/single-nic-linux-bridge-vlans/cinder-storage.yaml
+++ b/network/config/single-nic-linux-bridge-vlans/cinder-storage.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure VLANs for the
-  cinder storage role.
-
+  Software Config to drive os-net-config to configure VLANs for the cinder storage role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -65,7 +62,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -79,61 +76,62 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: linux_bridge
-              name: br-storage
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: linux_bridge
+                name: br-storage
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-              members:
-                -
-                  type: interface
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+                members:
+                - type: interface
                   name: nic1
                   # force the MAC address of the bridge to this interface
                   primary: true
-            -
-              type: vlan
-              vlan_id: {get_param: InternalApiNetworkVlanID}
-              device: br-storage
-              addresses:
-                -
-                  ip_netmask: {get_param: InternalApiIpSubnet}
-            -
-              type: vlan
-              vlan_id: {get_param: StorageNetworkVlanID}
-              device: br-storage
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageIpSubnet}
-            -
-              type: vlan
-              vlan_id: {get_param: StorageMgmtNetworkVlanID}
-              device: br-storage
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageMgmtIpSubnet}
+              - type: vlan
+                vlan_id:
+                  get_param: InternalApiNetworkVlanID
+                device: br-storage
+                addresses:
+                - ip_netmask:
+                    get_param: InternalApiIpSubnet
+              - type: vlan
+                vlan_id:
+                  get_param: StorageNetworkVlanID
+                device: br-storage
+                addresses:
+                - ip_netmask:
+                    get_param: StorageIpSubnet
+              - type: vlan
+                vlan_id:
+                  get_param: StorageMgmtNetworkVlanID
+                device: br-storage
+                addresses:
+                - ip_netmask:
+                    get_param: StorageMgmtIpSubnet
               # Uncomment when including environments/network-management.yaml
               # If setting default route on the Management interface, comment
               # out the default route on the Control Plane.
@@ -148,8 +146,9 @@ resources:
               #    -
               #      default: true
               #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/single-nic-linux-bridge-vlans/compute.yaml b/network/config/single-nic-linux-bridge-vlans/compute.yaml
index e31720d82b..aa63dd3aab 100644
--- a/network/config/single-nic-linux-bridge-vlans/compute.yaml
+++ b/network/config/single-nic-linux-bridge-vlans/compute.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure VLANs for the
-  compute role.
-
+  Software Config to drive os-net-config to configure VLANs for the compute role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -65,7 +62,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -79,68 +76,69 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: linux_bridge
-              name: {get_input: bridge_name}
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: linux_bridge
+                name: bridge_name
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-              members:
-                -
-                  type: interface
-                  name: {get_input: interface_name}
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+                members:
+                - type: interface
+                  name: interface_name
                   # force the MAC address of the bridge to this interface
                   primary: true
-            -
-              type: vlan
-              vlan_id: {get_param: InternalApiNetworkVlanID}
-              device: {get_input: bridge_name}
-              addresses:
-                -
-                  ip_netmask: {get_param: InternalApiIpSubnet}
-            -
-              type: vlan
-              vlan_id: {get_param: StorageNetworkVlanID}
-              device: {get_input: bridge_name}
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageIpSubnet}
-            -
-              type: vlan
-              vlan_id: {get_param: TenantNetworkVlanID}
-              device: {get_input: bridge_name}
-              addresses:
-                -
-                  ip_netmask: {get_param: TenantIpSubnet}
+              - type: vlan
+                vlan_id:
+                  get_param: InternalApiNetworkVlanID
+                device: bridge_name
+                addresses:
+                - ip_netmask:
+                    get_param: InternalApiIpSubnet
+              - type: vlan
+                vlan_id:
+                  get_param: StorageNetworkVlanID
+                device: bridge_name
+                addresses:
+                - ip_netmask:
+                    get_param: StorageIpSubnet
+              - type: vlan
+                vlan_id:
+                  get_param: TenantNetworkVlanID
+                device: bridge_name
+                addresses:
+                - ip_netmask:
+                    get_param: TenantIpSubnet
               # Uncomment when including environments/network-management.yaml
               # If setting default route on the Management interface, comment
               # out the default route on the Control Plane.
               #-
               #  type: vlan
               #  vlan_id: {get_param: ManagementNetworkVlanID}
-              #  device: {get_input: bridge_name}
+              #  device: bridge_name
               #  addresses:
               #    -
               #      ip_netmask: {get_param: ManagementIpSubnet}
@@ -148,8 +146,9 @@ resources:
               #    -
               #      default: true
               #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/single-nic-linux-bridge-vlans/controller-v6.yaml b/network/config/single-nic-linux-bridge-vlans/controller-v6.yaml
index a299d23e5b..28cf6ced7d 100644
--- a/network/config/single-nic-linux-bridge-vlans/controller-v6.yaml
+++ b/network/config/single-nic-linux-bridge-vlans/controller-v6.yaml
@@ -1,11 +1,7 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure VLANs for the
-  controller role with IPv6 on the External network. The IPv6 default
-  route is on the External network, and the IPv4 default route is on
-  the Control Plane.
-
+  Software Config to drive os-net-config to configure VLANs for the controller role with IPv6 on the External network. The
+  IPv6 default route is on the External network, and the IPv4 default route is on the Control Plane.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -63,7 +59,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute:
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: default route for the external network
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -81,78 +77,79 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: linux_bridge
-              name: {get_input: bridge_name}
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: linux_bridge
+                name: bridge_name
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-              members:
-                -
-                  type: interface
-                  name: {get_input: interface_name}
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+                members:
+                - type: interface
+                  name: interface_name
                   primary: true
-            -
-              type: vlan
-              vlan_id: {get_param: ExternalNetworkVlanID}
-              device: {get_input: bridge_name}
-              addresses:
-                -
-                  ip_netmask: {get_param: ExternalIpSubnet}
-              routes:
-                -
-                  default: true
-                  next_hop: {get_param: ExternalInterfaceDefaultRoute}
-            -
-              type: vlan
-              vlan_id: {get_param: InternalApiNetworkVlanID}
-              device: {get_input: bridge_name}
-              addresses:
-                -
-                  ip_netmask: {get_param: InternalApiIpSubnet}
-            -
-              type: vlan
-              vlan_id: {get_param: StorageNetworkVlanID}
-              device: {get_input: bridge_name}
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageIpSubnet}
-            -
-              type: vlan
-              vlan_id: {get_param: StorageMgmtNetworkVlanID}
-              device: {get_input: bridge_name}
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageMgmtIpSubnet}
-            -
-              type: vlan
-              vlan_id: {get_param: TenantNetworkVlanID}
-              device: {get_input: bridge_name}
-              addresses:
-                -
-                  ip_netmask: {get_param: TenantIpSubnet}
+              - type: vlan
+                vlan_id:
+                  get_param: ExternalNetworkVlanID
+                device: bridge_name
+                addresses:
+                - ip_netmask:
+                    get_param: ExternalIpSubnet
+                routes:
+                - default: true
+                  next_hop:
+                    get_param: ExternalInterfaceDefaultRoute
+              - type: vlan
+                vlan_id:
+                  get_param: InternalApiNetworkVlanID
+                device: bridge_name
+                addresses:
+                - ip_netmask:
+                    get_param: InternalApiIpSubnet
+              - type: vlan
+                vlan_id:
+                  get_param: StorageNetworkVlanID
+                device: bridge_name
+                addresses:
+                - ip_netmask:
+                    get_param: StorageIpSubnet
+              - type: vlan
+                vlan_id:
+                  get_param: StorageMgmtNetworkVlanID
+                device: bridge_name
+                addresses:
+                - ip_netmask:
+                    get_param: StorageMgmtIpSubnet
+              - type: vlan
+                vlan_id:
+                  get_param: TenantNetworkVlanID
+                device: bridge_name
+                addresses:
+                - ip_netmask:
+                    get_param: TenantIpSubnet
               # Uncomment when including environments/network-management.yaml
               # If setting default route on the Management interface, comment
               # out the default route on the External interface. This will
@@ -160,7 +157,7 @@ resources:
               #-
               #  type: vlan
               #  vlan_id: {get_param: ManagementNetworkVlanID}
-              #  device: {get_input: bridge_name}
+              #  device: bridge_name
               #  addresses:
               #    -
               #      ip_netmask: {get_param: ManagementIpSubnet}
@@ -168,8 +165,9 @@ resources:
               #    -
               #      default: true
               #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/single-nic-linux-bridge-vlans/controller.yaml b/network/config/single-nic-linux-bridge-vlans/controller.yaml
index bd97ccb0dc..566f1feb39 100644
--- a/network/config/single-nic-linux-bridge-vlans/controller.yaml
+++ b/network/config/single-nic-linux-bridge-vlans/controller.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure VLANs for the
-  controller role.
-
+  Software Config to drive os-net-config to configure VLANs for the controller role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -61,7 +58,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute:
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: default route for the external network
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -79,78 +76,79 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: linux_bridge
-              name: {get_input: bridge_name}
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: linux_bridge
+                name: bridge_name
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-              members:
-                -
-                  type: interface
-                  name: {get_input: interface_name}
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+                members:
+                - type: interface
+                  name: interface_name
                   primary: true
-            -
-              type: vlan
-              vlan_id: {get_param: ExternalNetworkVlanID}
-              device: {get_input: bridge_name}
-              addresses:
-                -
-                  ip_netmask: {get_param: ExternalIpSubnet}
-              routes:
-                -
-                  default: true
-                  next_hop: {get_param: ExternalInterfaceDefaultRoute}
-            -
-              type: vlan
-              vlan_id: {get_param: InternalApiNetworkVlanID}
-              device: {get_input: bridge_name}
-              addresses:
-                -
-                  ip_netmask: {get_param: InternalApiIpSubnet}
-            -
-              type: vlan
-              vlan_id: {get_param: StorageNetworkVlanID}
-              device: {get_input: bridge_name}
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageIpSubnet}
-            -
-              type: vlan
-              vlan_id: {get_param: StorageMgmtNetworkVlanID}
-              device: {get_input: bridge_name}
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageMgmtIpSubnet}
-            -
-              type: vlan
-              vlan_id: {get_param: TenantNetworkVlanID}
-              device: {get_input: bridge_name}
-              addresses:
-                -
-                  ip_netmask: {get_param: TenantIpSubnet}
+              - type: vlan
+                vlan_id:
+                  get_param: ExternalNetworkVlanID
+                device: bridge_name
+                addresses:
+                - ip_netmask:
+                    get_param: ExternalIpSubnet
+                routes:
+                - default: true
+                  next_hop:
+                    get_param: ExternalInterfaceDefaultRoute
+              - type: vlan
+                vlan_id:
+                  get_param: InternalApiNetworkVlanID
+                device: bridge_name
+                addresses:
+                - ip_netmask:
+                    get_param: InternalApiIpSubnet
+              - type: vlan
+                vlan_id:
+                  get_param: StorageNetworkVlanID
+                device: bridge_name
+                addresses:
+                - ip_netmask:
+                    get_param: StorageIpSubnet
+              - type: vlan
+                vlan_id:
+                  get_param: StorageMgmtNetworkVlanID
+                device: bridge_name
+                addresses:
+                - ip_netmask:
+                    get_param: StorageMgmtIpSubnet
+              - type: vlan
+                vlan_id:
+                  get_param: TenantNetworkVlanID
+                device: bridge_name
+                addresses:
+                - ip_netmask:
+                    get_param: TenantIpSubnet
               # Uncomment when including environments/network-management.yaml
               # If setting default route on the Management interface, comment
               # out the default route on the External interface. This will
@@ -158,7 +156,7 @@ resources:
               #-
               #  type: vlan
               #  vlan_id: {get_param: ManagementNetworkVlanID}
-              #  device: {get_input: bridge_name}
+              #  device: bridge_name
               #  addresses:
               #    -
               #      ip_netmask: {get_param: ManagementIpSubnet}
@@ -166,8 +164,9 @@ resources:
               #    -
               #      default: true
               #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/single-nic-linux-bridge-vlans/swift-storage.yaml b/network/config/single-nic-linux-bridge-vlans/swift-storage.yaml
index a5d2f966a1..fe948ad1ca 100644
--- a/network/config/single-nic-linux-bridge-vlans/swift-storage.yaml
+++ b/network/config/single-nic-linux-bridge-vlans/swift-storage.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure VLANs for the
-  swift storage role.
-
+  Software Config to drive os-net-config to configure VLANs for the swift storage role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -65,7 +62,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -79,61 +76,62 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: linux_bridge
-              name: br-storage
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: linux_bridge
+                name: br-storage
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-              members:
-                -
-                  type: interface
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+                members:
+                - type: interface
                   name: nic1
                   # force the MAC address of the bridge to this interface
                   primary: true
-            -
-              type: vlan
-              vlan_id: {get_param: InternalApiNetworkVlanID}
-              device: br-storage
-              addresses:
-                -
-                  ip_netmask: {get_param: InternalApiIpSubnet}
-            -
-              type: vlan
-              vlan_id: {get_param: StorageNetworkVlanID}
-              device: br-storage
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageIpSubnet}
-            -
-              type: vlan
-              vlan_id: {get_param: StorageMgmtNetworkVlanID}
-              device: br-storage
-              addresses:
-                -
-                  ip_netmask: {get_param: StorageMgmtIpSubnet}
+              - type: vlan
+                vlan_id:
+                  get_param: InternalApiNetworkVlanID
+                device: br-storage
+                addresses:
+                - ip_netmask:
+                    get_param: InternalApiIpSubnet
+              - type: vlan
+                vlan_id:
+                  get_param: StorageNetworkVlanID
+                device: br-storage
+                addresses:
+                - ip_netmask:
+                    get_param: StorageIpSubnet
+              - type: vlan
+                vlan_id:
+                  get_param: StorageMgmtNetworkVlanID
+                device: br-storage
+                addresses:
+                - ip_netmask:
+                    get_param: StorageMgmtIpSubnet
               # Uncomment when including environments/network-management.yaml
               # If setting default route on the Management interface, comment
               # out the default route on the Control Plane.
@@ -148,8 +146,9 @@ resources:
               #    -
               #      default: true
               #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/single-nic-vlans/ceph-storage.yaml b/network/config/single-nic-vlans/ceph-storage.yaml
index 6fa288afbd..6e0a97da98 100644
--- a/network/config/single-nic-vlans/ceph-storage.yaml
+++ b/network/config/single-nic-vlans/ceph-storage.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure VLANs for the
-  ceph storage role.
-
+  Software Config to drive os-net-config to configure VLANs for the ceph storage role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -53,7 +50,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -67,52 +64,53 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: ovs_bridge
-              name: br-storage
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: ovs_bridge
+                name: br-storage
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-              members:
-                -
-                  type: interface
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+                members:
+                - type: interface
                   name: nic1
                   # force the MAC address of the bridge to this interface
                   primary: true
-                -
-                  type: vlan
-                  vlan_id: {get_param: StorageNetworkVlanID}
+                - type: vlan
+                  vlan_id:
+                    get_param: StorageNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: StorageMgmtNetworkVlanID}
+                  - ip_netmask:
+                      get_param: StorageIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: StorageMgmtNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageMgmtIpSubnet}
+                  - ip_netmask:
+                      get_param: StorageMgmtIpSubnet
                 # Uncomment when including environments/network-management.yaml
                 # If setting default route on the Management interface, comment
                 # out the default route on the Control Plane.
@@ -126,8 +124,9 @@ resources:
                 #    -
                 #      default: true
                 #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/single-nic-vlans/cinder-storage.yaml b/network/config/single-nic-vlans/cinder-storage.yaml
index d113577634..f58665f7e1 100644
--- a/network/config/single-nic-vlans/cinder-storage.yaml
+++ b/network/config/single-nic-vlans/cinder-storage.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure VLANs for the
-  cinder storage role.
-
+  Software Config to drive os-net-config to configure VLANs for the cinder storage role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -57,7 +54,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -71,58 +68,59 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: ovs_bridge
-              name: br-storage
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: ovs_bridge
+                name: br-storage
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-              members:
-                -
-                  type: interface
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+                members:
+                - type: interface
                   name: nic1
                   # force the MAC address of the bridge to this interface
                   primary: true
-                -
-                  type: vlan
-                  vlan_id: {get_param: InternalApiNetworkVlanID}
+                - type: vlan
+                  vlan_id:
+                    get_param: InternalApiNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: InternalApiIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: StorageNetworkVlanID}
+                  - ip_netmask:
+                      get_param: InternalApiIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: StorageNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: StorageMgmtNetworkVlanID}
+                  - ip_netmask:
+                      get_param: StorageIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: StorageMgmtNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageMgmtIpSubnet}
+                  - ip_netmask:
+                      get_param: StorageMgmtIpSubnet
                 # Uncomment when including environments/network-management.yaml
                 # If setting default route on the Management interface, comment
                 # out the default route on the Control Plane.
@@ -136,8 +134,9 @@ resources:
                 #    -
                 #      default: true
                 #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/single-nic-vlans/compute.yaml b/network/config/single-nic-vlans/compute.yaml
index bd3cef3413..4026428488 100644
--- a/network/config/single-nic-vlans/compute.yaml
+++ b/network/config/single-nic-vlans/compute.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure VLANs for the
-  compute role.
-
+  Software Config to drive os-net-config to configure VLANs for the compute role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -57,7 +54,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -71,58 +68,59 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: ovs_bridge
-              name: {get_input: bridge_name}
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: ovs_bridge
+                name: bridge_name
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-              members:
-                -
-                  type: interface
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+                members:
+                - type: interface
                   name: nic1
                   # force the MAC address of the bridge to this interface
                   primary: true
-                -
-                  type: vlan
-                  vlan_id: {get_param: InternalApiNetworkVlanID}
+                - type: vlan
+                  vlan_id:
+                    get_param: InternalApiNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: InternalApiIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: StorageNetworkVlanID}
+                  - ip_netmask:
+                      get_param: InternalApiIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: StorageNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: TenantNetworkVlanID}
+                  - ip_netmask:
+                      get_param: StorageIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: TenantNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: TenantIpSubnet}
+                  - ip_netmask:
+                      get_param: TenantIpSubnet
                 # Uncomment when including environments/network-management.yaml
                 # If setting default route on the Management interface, comment
                 # out the default route on the Control Plane.
@@ -136,8 +134,9 @@ resources:
                 #    -
                 #      default: true
                 #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/single-nic-vlans/controller-no-external.yaml b/network/config/single-nic-vlans/controller-no-external.yaml
index 8e8b0f5df7..b9aec1eaeb 100644
--- a/network/config/single-nic-vlans/controller-no-external.yaml
+++ b/network/config/single-nic-vlans/controller-no-external.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure VLANs for the
-  controller role. No external IP is configured.
-
+  Software Config to drive os-net-config to configure VLANs for the controller role. No external IP is configured.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -61,7 +58,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute:
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: default route for the external network
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -79,64 +76,65 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: ovs_bridge
-              name: {get_input: bridge_name}
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: ovs_bridge
+                name: bridge_name
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-              members:
-                -
-                  type: interface
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+                members:
+                - type: interface
                   name: nic1
                   # force the MAC address of the bridge to this interface
                   primary: true
-                -
-                  type: vlan
-                  vlan_id: {get_param: InternalApiNetworkVlanID}
+                - type: vlan
+                  vlan_id:
+                    get_param: InternalApiNetworkVlanID
                   addresses:
-                  -
-                    ip_netmask: {get_param: InternalApiIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: StorageNetworkVlanID}
+                  - ip_netmask:
+                      get_param: InternalApiIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: StorageNetworkVlanID
                   addresses:
-                  -
-                    ip_netmask: {get_param: StorageIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: StorageMgmtNetworkVlanID}
+                  - ip_netmask:
+                      get_param: StorageIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: StorageMgmtNetworkVlanID
                   addresses:
-                  -
-                    ip_netmask: {get_param: StorageMgmtIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: TenantNetworkVlanID}
+                  - ip_netmask:
+                      get_param: StorageMgmtIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: TenantNetworkVlanID
                   addresses:
-                  -
-                    ip_netmask: {get_param: TenantIpSubnet}
+                  - ip_netmask:
+                      get_param: TenantIpSubnet
                 # Uncomment when including environments/network-management.yaml
                 # If setting default route on the Management interface, comment
                 # out the default route on the Control Plane.
@@ -150,8 +148,9 @@ resources:
                 #    -
                 #      default: true
                 #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/single-nic-vlans/controller-v6.yaml b/network/config/single-nic-vlans/controller-v6.yaml
index bf5656edfc..4f065d1ed1 100644
--- a/network/config/single-nic-vlans/controller-v6.yaml
+++ b/network/config/single-nic-vlans/controller-v6.yaml
@@ -1,11 +1,7 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure VLANs for the
-  controller role with IPv6 on the External network. The IPv6 default
-  route is on the External network, and the IPv4 default route is on
-  the Control Plane.
-
+  Software Config to drive os-net-config to configure VLANs for the controller role with IPv6 on the External network. The
+  IPv6 default route is on the External network, and the IPv4 default route is on the Control Plane.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -67,7 +63,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute:
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: default route for the external network
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -81,73 +77,74 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: ovs_bridge
-              name: {get_input: bridge_name}
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: ovs_bridge
+                name: bridge_name
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-              members:
-                -
-                  type: interface
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+                members:
+                - type: interface
                   name: nic1
                   primary: true
-                -
-                  type: vlan
-                  vlan_id: {get_param: ExternalNetworkVlanID}
+                - type: vlan
+                  vlan_id:
+                    get_param: ExternalNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: ExternalIpSubnet}
+                  - ip_netmask:
+                      get_param: ExternalIpSubnet
                   routes:
-                    -
-                      default: true
-                      next_hop: {get_param: ExternalInterfaceDefaultRoute}
-                -
-                  type: vlan
-                  vlan_id: {get_param: InternalApiNetworkVlanID}
+                  - default: true
+                    next_hop:
+                      get_param: ExternalInterfaceDefaultRoute
+                - type: vlan
+                  vlan_id:
+                    get_param: InternalApiNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: InternalApiIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: StorageNetworkVlanID}
+                  - ip_netmask:
+                      get_param: InternalApiIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: StorageNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: StorageMgmtNetworkVlanID}
+                  - ip_netmask:
+                      get_param: StorageIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: StorageMgmtNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageMgmtIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: TenantNetworkVlanID}
+                  - ip_netmask:
+                      get_param: StorageMgmtIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: TenantNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: TenantIpSubnet}
+                  - ip_netmask:
+                      get_param: TenantIpSubnet
                 # Uncomment when including environments/network-management.yaml
                 # If setting default route on the Management interface, comment
                 # out the default route on the External interface. This will
@@ -162,8 +159,9 @@ resources:
                 #    -
                 #      default: true
                 #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/single-nic-vlans/controller.yaml b/network/config/single-nic-vlans/controller.yaml
index c5979a89b2..4a615d91da 100644
--- a/network/config/single-nic-vlans/controller.yaml
+++ b/network/config/single-nic-vlans/controller.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure VLANs for the
-  controller role.
-
+  Software Config to drive os-net-config to configure VLANs for the controller role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -61,7 +58,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute:
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: default route for the external network
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -79,71 +76,72 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: ovs_bridge
-              name: {get_input: bridge_name}
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: ovs_bridge
+                name: bridge_name
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-              members:
-                -
-                  type: interface
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                members:
+                - type: interface
                   name: nic1
                   # force the MAC address of the bridge to this interface
                   primary: true
-                -
-                  type: vlan
-                  vlan_id: {get_param: ExternalNetworkVlanID}
+                - type: vlan
+                  vlan_id:
+                    get_param: ExternalNetworkVlanID
                   addresses:
-                  -
-                    ip_netmask: {get_param: ExternalIpSubnet}
+                  - ip_netmask:
+                      get_param: ExternalIpSubnet
                   routes:
-                    -
-                      default: true
-                      next_hop: {get_param: ExternalInterfaceDefaultRoute}
-                -
-                  type: vlan
-                  vlan_id: {get_param: InternalApiNetworkVlanID}
+                  - default: true
+                    next_hop:
+                      get_param: ExternalInterfaceDefaultRoute
+                - type: vlan
+                  vlan_id:
+                    get_param: InternalApiNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: InternalApiIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: StorageNetworkVlanID}
+                  - ip_netmask:
+                      get_param: InternalApiIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: StorageNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: StorageMgmtNetworkVlanID}
+                  - ip_netmask:
+                      get_param: StorageIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: StorageMgmtNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageMgmtIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: TenantNetworkVlanID}
+                  - ip_netmask:
+                      get_param: StorageMgmtIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: TenantNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: TenantIpSubnet}
+                  - ip_netmask:
+                      get_param: TenantIpSubnet
                 # Uncomment when including environments/network-management.yaml
                 # If setting default route on the Management interface, comment
                 # out the default route on the External interface. This will
@@ -158,8 +156,9 @@ resources:
                 #    -
                 #      default: true
                 #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/config/single-nic-vlans/swift-storage.yaml b/network/config/single-nic-vlans/swift-storage.yaml
index 7b06580cf0..88f69b4d81 100644
--- a/network/config/single-nic-vlans/swift-storage.yaml
+++ b/network/config/single-nic-vlans/swift-storage.yaml
@@ -1,9 +1,6 @@
-heat_template_version: 2015-04-30
-
+heat_template_version: '2016-10-14'
 description: >
-  Software Config to drive os-net-config to configure VLANs for the
-  swift storage role.
-
+  Software Config to drive os-net-config to configure VLANs for the swift storage role.
 parameters:
   ControlPlaneIp:
     default: ''
@@ -57,7 +54,7 @@ parameters:
     description: The default route of the control plane network.
     type: string
   ExternalInterfaceDefaultRoute: # Not used by default in this template
-    default: '10.0.0.1'
+    default: 10.0.0.1
     description: The default route of the external network.
     type: string
   ManagementInterfaceDefaultRoute: # Commented out by default in this template
@@ -71,58 +68,59 @@ parameters:
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
-
 resources:
   OsNetConfigImpl:
-    type: OS::Heat::StructuredConfig
+    type: OS::Heat::SoftwareConfig
     properties:
-      group: os-apply-config
+      group: script
       config:
-        os_net_config:
-          network_config:
-            -
-              type: ovs_bridge
-              name: br-storage
-              use_dhcp: false
-              dns_servers: {get_param: DnsServers}
-              addresses:
-                -
-                  ip_netmask:
+        str_replace:
+          template:
+            get_file: ../../scripts/run-os-net-config.sh
+          params:
+            $network_config:
+              network_config:
+              - type: ovs_bridge
+                name: br-storage
+                use_dhcp: false
+                dns_servers:
+                  get_param: DnsServers
+                addresses:
+                - ip_netmask:
                     list_join:
-                      - '/'
-                      - - {get_param: ControlPlaneIp}
-                        - {get_param: ControlPlaneSubnetCidr}
-              routes:
-                -
-                  ip_netmask: 169.254.169.254/32
-                  next_hop: {get_param: EC2MetadataIp}
-                -
-                  default: true
-                  next_hop: {get_param: ControlPlaneDefaultRoute}
-              members:
-                -
-                  type: interface
+                    - /
+                    - - get_param: ControlPlaneIp
+                      - get_param: ControlPlaneSubnetCidr
+                routes:
+                - ip_netmask: 169.254.169.254/32
+                  next_hop:
+                    get_param: EC2MetadataIp
+                - default: true
+                  next_hop:
+                    get_param: ControlPlaneDefaultRoute
+                members:
+                - type: interface
                   name: nic1
                   # force the MAC address of the bridge to this interface
                   primary: true
-                -
-                  type: vlan
-                  vlan_id: {get_param: InternalApiNetworkVlanID}
+                - type: vlan
+                  vlan_id:
+                    get_param: InternalApiNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: InternalApiIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: StorageNetworkVlanID}
+                  - ip_netmask:
+                      get_param: InternalApiIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: StorageNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageIpSubnet}
-                -
-                  type: vlan
-                  vlan_id: {get_param: StorageMgmtNetworkVlanID}
+                  - ip_netmask:
+                      get_param: StorageIpSubnet
+                - type: vlan
+                  vlan_id:
+                    get_param: StorageMgmtNetworkVlanID
                   addresses:
-                    -
-                      ip_netmask: {get_param: StorageMgmtIpSubnet}
+                  - ip_netmask:
+                      get_param: StorageMgmtIpSubnet
                 # Uncomment when including environments/network-management.yaml
                 # If setting default route on the Management interface, comment
                 # out the default route on the Control Plane.
@@ -136,8 +134,9 @@ resources:
                 #    -
                 #      default: true
                 #      next_hop: {get_param: ManagementInterfaceDefaultRoute}
-
 outputs:
   OS::stack_id:
     description: The OsNetConfigImpl resource.
-    value: {get_resource: OsNetConfigImpl}
+    value:
+      get_resource: OsNetConfigImpl
+
diff --git a/network/scripts/run-os-net-config.sh b/network/scripts/run-os-net-config.sh
new file mode 100755
index 0000000000..fc1e6d54b7
--- /dev/null
+++ b/network/scripts/run-os-net-config.sh
@@ -0,0 +1,136 @@
+#!/bin/bash
+# Note this script expects the following environment variables to be set
+# normally these are provided by the calling SoftwareConfig resource, but
+# they may also be set manually for testing
+# $bridge_name : The bridge device name to apply
+# $interface_name : The interface name to apply
+#
+# Also this token is replaced via a str_replace in the SoftwareConfig running
+# the script - in future we may extend this to also work with a variable, e.g
+# a deployment input via input_values
+# $network_config : the json serialized os-net-config config to apply
+#
+set -ux
+
+function get_metadata_ip() {
+
+  local METADATA_IP
+
+  # Look for a variety of Heat transports
+  # FIXME: Heat should provide a way to obtain this in a single place
+  for URL in os-collect-config.cfn.metadata_url os-collect-config.heat.auth_url os-collect-config.request.metadata_url os-collect-config.zaqar.auth_url; do
+    METADATA_IP=$(os-apply-config --key $URL --key-default '' --type raw 2>/dev/null | sed -e 's|http.*://\([^:]*\).*|\1|')
+    [ -n "$METADATA_IP" ] && break
+  done
+
+  echo $METADATA_IP
+
+}
+
+function is_local_ip() {
+  local IP_TO_CHECK=$1
+  if ip -o a | grep "inet6\? $IP_TO_CHECK/" &>/dev/null; then
+    return 0
+  else
+    return 1
+  fi
+}
+
+function ping_metadata_ip() {
+  local METADATA_IP=$(get_metadata_ip)
+
+  if [ -n "$METADATA_IP" ] && ! is_local_ip $METADATA_IP; then
+
+    echo -n "Trying to ping metadata IP ${METADATA_IP}..."
+
+    local COUNT=0
+    until ping -c 1 $METADATA_IP &> /dev/null; do
+      COUNT=$(( $COUNT + 1 ))
+      if [ $COUNT -eq 10 ]; then
+        echo "FAILURE"
+        echo "$METADATA_IP is not pingable." >&2
+        exit 1
+      fi
+    done
+    echo "SUCCESS"
+
+  else
+    echo "No metadata IP found. Skipping."
+  fi
+}
+
+function configure_safe_defaults() {
+
+[[ $? == 0 ]] && return 0
+
+cat > /etc/os-net-config/dhcp_all_interfaces.yaml <<EOF_CAT
+# This file is an autogenerated safe defaults file for os-net-config
+# which runs DHCP on all discovered interfaces to ensure connectivity
+# back to the undercloud for updates
+network_config:
+EOF_CAT
+
+    for iface in $(ls /sys/class/net | grep -v ^lo$); do
+        local mac_addr_type="$(cat /sys/class/net/${iface}/addr_assign_type)"
+        if [ "$mac_addr_type" != "0" ]; then
+            echo "Device has generated MAC, skipping."
+        else
+            ip link set dev $iface up &>/dev/null
+            HAS_LINK="$(cat /sys/class/net/${iface}/carrier)"
+
+            TRIES=10
+            while [ "$HAS_LINK" == "0" -a $TRIES -gt 0 ]; do
+                HAS_LINK="$(cat /sys/class/net/${iface}/carrier)"
+                if [ "$HAS_LINK" == "1" ]; then
+                    break
+                else
+                    sleep 1
+                fi
+                TRIES=$(( TRIES - 1 ))
+            done
+            if [ "$HAS_LINK" == "1" ] ; then
+cat >> /etc/os-net-config/dhcp_all_interfaces.yaml <<EOF_CAT
+  -
+    type: interface
+    name: $iface
+    use_dhcp: true
+EOF_CAT
+            fi
+        fi
+    done
+    os-net-config -c /etc/os-net-config/dhcp_all_interfaces.yaml -v --detailed-exit-codes --cleanup
+    RETVAL=$?
+    if [[ $RETVAL == 2 ]]; then
+        ping_metadata_ip
+    elif [[ $RETVAL != 0 ]]; then
+        echo "ERROR: configuration of safe defaults failed."
+    fi
+}
+
+if [ -n '$network_config' ]; then
+    trap configure_safe_defaults EXIT
+
+    mkdir -p /etc/os-net-config
+    # Note these variables come from the calling heat SoftwareConfig
+    echo '$network_config' > /etc/os-net-config/config.json
+    sed -i "s/bridge_name/$bridge_name/" /etc/os-net-config/config.json
+    sed -i "s/interface_name/$interface_name/" /etc/os-net-config/config.json
+
+    os-net-config -c /etc/os-net-config/config.json -v --detailed-exit-codes
+    RETVAL=$?
+    if [[ $RETVAL == 2 ]]; then
+        ping_metadata_ip
+
+        #NOTE: dprince this udev rule can apparently leak DHCP processes?
+        # https://bugs.launchpad.net/tripleo/+bug/1538259
+        # until we discover the root cause we can simply disable the
+        # rule because networking has already been configured at this point
+        if [ -f /etc/udev/rules.d/99-dhcp-all-interfaces.rules ]; then
+            rm /etc/udev/rules.d/99-dhcp-all-interfaces.rules
+        fi
+
+    elif [[ $RETVAL != 0 ]]; then
+        echo "ERROR: os-net-config configuration failed." >&2
+        exit 1
+    fi
+fi
diff --git a/tools/yaml-nic-config-2-script.py b/tools/yaml-nic-config-2-script.py
new file mode 100755
index 0000000000..b8f07e4f0f
--- /dev/null
+++ b/tools/yaml-nic-config-2-script.py
@@ -0,0 +1,219 @@
+#!/usr/bin/env python
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import collections
+import copy
+import os
+import sys
+import traceback
+import yaml
+import six
+import re
+
+
+#convert comments into 'comments<num>: ...' YAML
+def to_commented_yaml(filename):
+    out_str = ''
+    last_non_comment_spaces = ''
+    with open(filename, 'r') as f:
+        comment_count = 0
+        for line in f:
+            char_count = 0
+            spaces = ''
+            for char in line:
+                char_count += 1
+                if char == ' ':
+                    spaces+=' '
+                    next;
+                elif char == '#':
+                    comment_count += 1
+                    comment = line[char_count:-1]
+                    out_str += "%scomment%i_%i: '%s'\n" % (last_non_comment_spaces, comment_count, len(spaces), comment)
+                    break;
+                else:
+                    last_non_comment_spaces = spaces
+                    out_str += line
+
+                    #inline comments check
+                    m = re.match(".*:.*#(.*)", line)
+                    if m:
+                        comment_count += 1
+                        out_str += "%s  inline_comment%i: '%s'\n" % (last_non_comment_spaces, comment_count, m.group(1))
+                    break;
+
+    with open(filename, 'w') as f:
+        f.write(out_str)
+
+    return out_str
+
+#convert back to normal #commented YAML
+def to_normal_yaml(filename):
+
+    with open(filename, 'r') as f:
+        data = f.read()
+
+    out_str = ''
+    next_line_break = False
+    for line in data.split('\n'):
+        m = re.match(" +comment[0-9]+_([0-9]+): '(.*)'.*", line) #normal comments
+        i = re.match(" +inline_comment[0-9]+: '(.*)'.*", line) #inline comments
+        if m:
+            if next_line_break:
+                out_str += '\n'
+                next_line_break = False
+            for x in range(0, int(m.group(1))):
+                out_str += " "
+            out_str += "#%s\n" % m.group(2)
+        elif i:
+            out_str += " #%s\n" % i.group(1)
+            next_line_break = False
+        else:
+            if next_line_break:
+                out_str += '\n'
+            out_str += line
+            next_line_break = True
+
+    if next_line_break:
+        out_str += '\n'
+
+    with open(filename, 'w') as f:
+        f.write(out_str)
+
+    return out_str
+
+
+class description(six.text_type):
+    pass
+
+# FIXME: Some of this duplicates code from build_endpoint_map.py, we should
+# refactor to share the common code
+class TemplateDumper(yaml.SafeDumper):
+    def represent_ordered_dict(self, data):
+        return self.represent_dict(data.items())
+
+    def description_presenter(self, data):
+        if '\n' in data:
+            style = '>'
+        else:
+            style = ''
+        return self.represent_scalar(
+            yaml.resolver.BaseResolver.DEFAULT_SCALAR_TAG, data, style=style)
+
+
+# We load mappings into OrderedDict to preserve their order
+class TemplateLoader(yaml.SafeLoader):
+    def construct_mapping(self, node):
+        self.flatten_mapping(node)
+        return collections.OrderedDict(self.construct_pairs(node))
+
+
+TemplateDumper.add_representer(description,
+                               TemplateDumper.description_presenter)
+
+TemplateDumper.add_representer(collections.OrderedDict,
+                               TemplateDumper.represent_ordered_dict)
+
+
+TemplateLoader.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
+                               TemplateLoader.construct_mapping)
+
+def write_template(template, filename=None):
+    with open(filename, 'w') as f:
+        yaml.dump(template, f, TemplateDumper, width=120, default_flow_style=False)
+
+def exit_usage():
+    print('Usage %s <yaml file>' % sys.argv[0])
+    sys.exit(1)
+
+def convert(filename):
+    print('Converting %s' % filename)
+    try:
+        tpl = yaml.load(open(filename).read(), Loader=TemplateLoader)
+    except Exception:
+        print(traceback.format_exc())
+        return 0
+
+    # Check which path we need for run-os-net-config.sh because we have
+    # nic config templates in the top-level and network/config
+    script_paths = ['network/scripts/run-os-net-config.sh',
+                    '../../scripts/run-os-net-config.sh']
+    script_path = None
+    for p in script_paths:
+        check_path = os.path.join(os.path.dirname(filename), p)
+        if os.path.isfile(check_path):
+            print("Found %s, using %s" % (check_path, p))
+            script_path = p
+    if script_path is None:
+        print("Error couldn't find run-os-net-config.sh relative to filename")
+        exit_usage()
+
+    for r in six.iteritems(tpl.get('resources', {})):
+        if (r[1].get('type') == 'OS::Heat::StructuredConfig' and
+            r[1].get('properties', {}).get('group') == 'os-apply-config' and
+            r[1].get('properties', {}).get('config', {}).get('os_net_config')):
+            #print("match %s" % r[0])
+            new_r = collections.OrderedDict()
+            new_r['type'] = 'OS::Heat::SoftwareConfig'
+            new_r['properties'] = collections.OrderedDict()
+            new_r['properties']['group'] = 'script'
+            old_net_config = r[1].get(
+                'properties', {}).get('config', {}).get('os_net_config')
+            new_config = {'str_replace': collections.OrderedDict()}
+            new_config['str_replace']['template'] = {'get_file': script_path}
+            new_config['str_replace']['params'] = {'$network_config': old_net_config}
+            new_r['properties']['config'] = new_config
+            tpl['resources'][r[0]] = new_r
+        else:
+            print("No match %s" % r[0])
+            return 0
+
+    # Preserve typical HOT template key ordering
+    od_result = collections.OrderedDict()
+    # Need to bump the HOT version so str_replace supports serializing to json
+    od_result['heat_template_version'] = "2016-10-14"
+    if tpl.get('description'):
+        od_result['description'] = description(tpl['description'])
+    od_result['parameters'] = tpl['parameters']
+    od_result['resources'] = tpl['resources']
+    od_result['outputs'] = tpl['outputs']
+    #print('Result:')
+    #print('%s' % yaml.dump(od_result, Dumper=TemplateDumper, width=120, default_flow_style=False))
+    #print('---')
+    #replace = raw_input(
+        #"Replace file %s?  Answer y/n" % filename).lower() == 'y'
+    #if replace:
+    #print("Replace %s" % filename)
+    write_template(od_result, filename)
+    #else:
+    #    print("NOT replacing %s" % filename)
+    #    return 0
+    return 1
+
+if len(sys.argv) < 2:
+    exit_usage()
+
+path_args = sys.argv[1:]
+exit_val = 0
+num_converted = 0
+
+for base_path in path_args:
+    if os.path.isfile(base_path) and base_path.endswith('.yaml'):
+        to_commented_yaml(base_path)
+        num_converted += convert(base_path)
+        to_normal_yaml(base_path)
+    else:
+        print('Unexpected argument %s' % base_path)
+        exit_usage()
+if num_converted == 0:
+  exit_val = 1
+sys.exit(exit_val)