Add multirack context

Related-Prod: PRODX-3456
Change-Id: If9a79e0727407a759b42bbdcc74d597226cae3bb
diff --git a/de/heat-templates/env/main-wrkr3-rack1-cmp3-rack2-cmp3.yaml b/de/heat-templates/env/main-wrkr3-rack1-cmp3-rack2-cmp3.yaml
new file mode 100644
index 0000000..a08911e
--- /dev/null
+++ b/de/heat-templates/env/main-wrkr3-rack1-cmp3-rack2-cmp3.yaml
@@ -0,0 +1,41 @@
+resource_registry:
+  "MCP2::CentralSite": ../fragments/multirack/CentralSite.yaml
+  "MCP2::Rack": ../fragments/multirack/Rack.yaml
+  "MCP2::RackRouterRoutes": ../fragments/multirack/RackRouterRoutes.yaml
+
+parameters:
+  image: bionic-server-cloudimg-amd64-20190612
+  public_net_id: public
+  main_worker_size: 3
+  rack01_cmp_size: 3
+  rack02_cmp_size: 3
+  cluster_public_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCp0evjOaK8c8SKYK4r2+0BN7g+8YSvQ2n8nFgOURCyvkJqOHi1qPGZmuN0CclYVdVuZiXbWw3VxRbSW3EH736VzgY1U0JmoTiSamzLHaWsXvEIW8VCi7boli539QJP0ikJiBaNAgZILyCrVPN+A6mfqtacs1KXdZ0zlMq1BPtFciR1JTCRcVs5vP2Wwz5QtY2jMIh3aiwkePjMTQPcfmh1TkOlxYu5IbQyZ3G1ahA0mNKI9a0dtF282av/F6pwB/N1R1nEZ/9VtcN2I1mf1NW/tTHEEcTzXYo1R/8K9vlqAN8QvvGLZtZduGviNVNoNWvoxaXxDt8CPv2B2NCdQFZp
+  tunnel_interface: 'ens3'
+  main_worker_metadata: {"labels": {"openstack-control-plane":"enabled","openvswitch":"enabled","openstack-gateway": "enabled","role":"ceph-osd-node","local-volume-provisioner": "enabled"}}
+  rack01_cmp_metadata: {"labels": {"openstack-compute-node":"enabled","openvswitch":"enabled"}}
+  rack02_cmp_metadata: {"labels": {"openstack-compute-node":"enabled","openvswitch":"enabled"}}
+  # hardware_metadata which is used for Ceph requires flavor with
+  # ephemeral storage because it is used for Ceph bluestore.
+  main_worker_flavor: 'system.compact.openstack.control.ephemeral'
+  rack01_cmp_flavor: 'system.compact.openstack.control.ephemeral'
+  docker_ucp_image: docker-dev-kaas-local.docker.mirantis.net/lcm/docker/ucp:3.3.3
+  docker_ee_url: https://storebits.docker.com/ubuntu
+  docker_ee_release: stable-19.03
+  main_worker_hardware_metadata: |
+    '00:00:00:00:00:00':
+      write_files:
+        - path: /usr/share/metadata/ceph.yaml
+          content: |
+            storageDevices:
+              - name: vdb
+                role: hdd
+                sizeGb: 20
+            ramGb: 8
+            cores: 2
+            # The roles will be assigned based on node labels.
+            # roles:
+            #   - mon
+            #   - mgr
+            ips:
+              - 192.168.122.101
+            crushPath: {}
diff --git a/de/heat-templates/fragments/multirack/CentralSite.yaml b/de/heat-templates/fragments/multirack/CentralSite.yaml
new file mode 100644
index 0000000..ff05a71
--- /dev/null
+++ b/de/heat-templates/fragments/multirack/CentralSite.yaml
@@ -0,0 +1,206 @@
+heat_template_version: queens
+
+parameters:
+
+  ucp_metadata:
+    type: json
+    default: {}
+  key_name:
+    type: string
+    description: Name of keypair to assign to servers
+  image:
+    type: string
+    description: Name of image to use for servers
+  ucp_flavor:
+    type: string
+    description: Flavor to use for servers
+  boot_timeout:
+    type: number
+    description: Boot timeout for instance
+    default: 3600
+  public_net_id:
+    type: string
+  docker_ee_release:
+    type: string
+  docker_ee_url:
+    type: string
+  docker_ucp_image:
+    type: string
+    default: 'docker/ucp:3.2.4'
+  worker_hardware_metadata:
+    description: The content of lab metadata.
+    default: ''
+    type: string
+
+  control_network_cidr:
+    description: The CIDR for control network
+    type: string
+  tunnel_network_cidr:
+    description: The CIDR for control network
+    type: string
+  storage_backend_network_cidr:
+    description: The CIDR for control network
+    type: string
+  storage_frontend_network_cidr:
+    description: The CIDR for control network
+    type: string
+  private_floating_network_cidr:
+    description: The CIDR for control network
+    type: string
+  private_floating_network_interface:
+    description: The CIDR for control network
+    type: string
+  worker_size:
+    type: number
+  worker_metadata:
+    type: json
+  worker_flavor:
+    type: string
+
+resources:
+  router:
+    type: OS::Neutron::Router
+    properties:
+      external_gateway_info:
+        network: { get_param: public_net_id }
+
+  control_network:
+    type: OS::Neutron::Net
+  control_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network: { get_resource: control_network }
+      enable_dhcp: true
+      cidr: { get_param: control_network_cidr }
+      dns_nameservers:
+        - 172.18.224.6
+        - 172.18.176.6
+
+  router_control_iface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router: { get_resource: router }
+      subnet: { get_resource: control_subnet }
+
+  tunnel_network:
+    type: OS::Neutron::Net
+  tunnel_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network: { get_resource: tunnel_network }
+      enable_dhcp: true
+      cidr: { get_param: tunnel_network_cidr }
+
+  router_tunnel_iface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router: { get_resource: router }
+      subnet: { get_resource: tunnel_subnet }
+
+  storage_frontend_network:
+    type: OS::Neutron::Net
+  storage_frontend_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network: { get_resource: storage_frontend_network }
+      enable_dhcp: true
+      cidr: { get_param: storage_frontend_network_cidr }
+
+  router_storage_frontend_iface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router: { get_resource: router }
+      subnet: { get_resource: storage_frontend_subnet }
+
+  storage_backend_network:
+    type: OS::Neutron::Net
+  storage_backend_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network: { get_resource: storage_backend_network }
+      enable_dhcp: true
+      cidr: { get_param: storage_backend_network_cidr }
+
+  router_storage_backend_iface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router: { get_resource: router }
+      subnet: { get_resource: storage_backend_subnet }
+
+
+  private_floating_network:
+    type: OS::Neutron::Net
+  private_floating_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      gateway_ip: ~
+      network: { get_resource: private_floating_network }
+      enable_dhcp: true
+      cidr: { get_param: private_floating_network_cidr }
+
+
+  ucp:
+    depends_on:
+    - router_control_iface
+    type: ./SrvInstancesVM.yaml
+    properties:
+      metadata: { get_param: ucp_metadata}
+      docker_ee_url: { get_param: docker_ee_url }
+      docker_ee_release: { get_param: docker_ee_release }
+      docker_ucp_image: { get_param: docker_ucp_image}
+      node_type: "ucp"
+      key_name: { get_param: key_name }
+      image: { get_param: image }
+      flavor: { get_param: ucp_flavor }
+      control_network: { get_resource: control_network }
+      private_floating_network: { get_resource: private_floating_network }
+      private_floating_subnet_id: { get_resource: private_floating_subnet }
+      private_floating_interface: { get_param: private_floating_network_interface }
+      private_floating_network_cidr: { get_param: private_floating_network_cidr }
+      control_subnet_id: { get_resource: control_subnet }
+      public_net_id: { get_param: public_net_id }
+      control_network_cidr: { get_param: control_network_cidr }
+
+  worker:
+    type: OS::Heat::ResourceGroup
+    depends_on:
+     - ucp
+    properties:
+      count: { get_param: worker_size }
+      resource_def:
+        type: ./SrvInstancesVMCeph.yaml
+        properties:
+          metadata: { get_param: worker_metadata}
+          ucp_master_host: { get_attr: [ucp, server_control_ip] }
+          docker_ee_url: { get_param: docker_ee_url }
+          docker_ee_release: { get_param: docker_ee_release }
+          docker_ucp_image: { get_param: docker_ucp_image}
+          node_type: "worker"
+          key_name: { get_param: key_name }
+          image: { get_param: image }
+          flavor: { get_param: worker_flavor }
+          control_network: { get_resource: control_network }
+          control_subnet_id: { get_resource: control_subnet }
+          control_network_cidr: { get_param: control_network_cidr }
+          private_floating_network: { get_resource: private_floating_network }
+          private_floating_subnet_id: { get_resource: private_floating_subnet }
+          private_floating_interface: { get_param: private_floating_network_interface }
+          private_floating_network_cidr: { get_param: private_floating_network_cidr }
+          public_net_id: { get_param: public_net_id }
+          hardware_metadata: { get_param: worker_hardware_metadata}
+
+outputs:
+  worker_public_ip:
+    description: IP address of server in private network
+    value: { get_attr: [worker, server_public_ip] }
+  ucp_public_ip:
+    description: IP address of server in private network
+    value: { get_attr: [ucp, server_public_ip] }
+  ucp_control_ip:                
+    description: IP address of server in private network
+    value: { get_attr: [ucp, server_control_ip] }
+  worker_wc_data:
+    description: Metadata from instance
+    value: { get_attr: [worker, wc_data]}
+  router_id:
+    value: { get_resource: router }
diff --git a/de/heat-templates/fragments/multirack/Rack.yaml b/de/heat-templates/fragments/multirack/Rack.yaml
new file mode 100644
index 0000000..83b6927
--- /dev/null
+++ b/de/heat-templates/fragments/multirack/Rack.yaml
@@ -0,0 +1,83 @@
+heat_template_version: queens
+
+parameters:
+
+  key_name:
+    type: string
+    description: Name of keypair to assign to servers
+  image:
+    type: string
+    description: Name of image to use for servers
+  cmp_flavor:
+    type: string
+    description: Flavor to use for servers
+  cmp_size:
+    type: number
+  cmp_metadata:
+    type: json
+    default: {}
+  boot_timeout:
+    type: number
+    description: Boot timeout for instance
+    default: 3600
+  ucp_master_host:
+    type: string
+  public_net_id:
+    type: string
+  docker_ee_release:
+    type: string
+  docker_ee_url:
+    type: string
+  docker_ucp_image:
+    type: string
+  control_network_cidr:
+    description: The CIDR for control network
+    type: string
+  rack_router:
+    type: string
+resources:
+
+  control_network:
+    type: OS::Neutron::Net
+  control_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network: { get_resource: control_network }
+      enable_dhcp: true
+      cidr: { get_param: control_network_cidr }
+      dns_nameservers:
+        - 172.18.224.6
+        - 172.18.176.6
+
+  router_control_iface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router: { get_param: rack_router }
+      subnet: { get_resource: control_subnet }
+
+  cmp:
+    depends_on:
+    - router_control_iface
+    type: ./SrvInstancesVMRack.yaml
+    properties:
+      metadata: { get_param: cmp_metadata}
+      docker_ee_url: { get_param: docker_ee_url }
+      docker_ee_release: { get_param: docker_ee_release }
+      docker_ucp_image: { get_param: docker_ucp_image}
+      node_type: "worker"
+      key_name: { get_param: key_name }
+      image: { get_param: image }
+      flavor: { get_param: cmp_flavor }
+      control_network: { get_resource: control_network }
+      control_subnet_id: { get_resource: control_subnet }
+      public_net_id: { get_param: public_net_id }
+      control_network_cidr: { get_param: control_network_cidr }
+      ucp_master_host: { get_param: ucp_master_host }
+
+outputs:
+  cmp_public_ip:
+    description: IP address of server in private network
+    value: { get_attr: [cmp, server_public_ip] }
+  cmp_wc_data:
+    description: Metadata from instance
+    value: { get_attr: [cmp, wc_data] }
diff --git a/de/heat-templates/fragments/multirack/RackRouterRoutes.yaml b/de/heat-templates/fragments/multirack/RackRouterRoutes.yaml
new file mode 100644
index 0000000..0e90b3b
--- /dev/null
+++ b/de/heat-templates/fragments/multirack/RackRouterRoutes.yaml
@@ -0,0 +1,99 @@
+heat_template_version: queens
+
+parameters:
+  public_net_id:
+    type: string
+  central_router:
+    type: string
+  central_router_uplink_network_cidr:
+    type: string
+  site_cidr:
+    type: string
+  lab_network_cidr:
+    type: string
+
+resources:
+  router:
+    type: OS::Neutron::Router
+    properties:
+      external_gateway_info:
+        network: { get_param: public_net_id }
+
+  uplink_network:
+    type: OS::Neutron::Net
+  uplink_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network: { get_resource: uplink_network }
+      enable_dhcp: true
+      cidr: { get_param: central_router_uplink_network_cidr }
+
+  central_router_uplink_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_resource: uplink_network }
+      port_security_enabled: false
+      fixed_ips:
+      - subnet: { get_resource: uplink_subnet }
+
+  central_router_uplink_interface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router: { get_param: central_router }
+      port: { get_resource: central_router_uplink_port }
+
+  rack_router_uplink_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_resource: uplink_network }
+      port_security_enabled: false
+      fixed_ips:
+      - subnet: { get_resource: uplink_subnet }
+
+  rack_router_uplink_interface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router: { get_resource: router }
+      port: { get_resource: rack_router_uplink_port }
+
+  wait01:
+    depends_on:
+    - rack_router_uplink_port
+    - central_router_uplink_interface
+    - central_router_uplink_port
+    - rack_router_uplink_interface
+    type: OS::Heat::TestResource
+    properties:
+      action_wait_secs:
+        create: 30
+
+  central_to_rack:
+    type: OS::Neutron::ExtraRoute
+    depends_on:
+    - wait01
+    properties:
+      destination: { get_param: site_cidr }
+      nexthop: { get_attr: [rack_router_uplink_port, fixed_ips, 0, ip_address] }
+      router_id: { get_param: central_router }
+
+  wait02:
+    depends_on:
+    - central_to_rack
+    type: OS::Heat::TestResource
+    properties:
+      action_wait_secs:
+        create: 30
+
+  rack_to_central:
+    type: OS::Neutron::ExtraRoute
+    depends_on:
+     - wait02
+    properties:
+      destination: { get_param: lab_network_cidr }
+      nexthop: { get_attr: [central_router_uplink_port, fixed_ips, 0, ip_address] }
+      router_id: { get_resource: router }
+
+
+outputs:
+  router_id:
+    value: { get_resource: router }
diff --git a/de/heat-templates/fragments/multirack/SrvInstancesVM.yaml b/de/heat-templates/fragments/multirack/SrvInstancesVM.yaml
new file mode 100644
index 0000000..cf4983f
--- /dev/null
+++ b/de/heat-templates/fragments/multirack/SrvInstancesVM.yaml
@@ -0,0 +1,155 @@
+heat_template_version: queens
+
+parameters:
+
+  metadata:
+    type: json
+    default: {}
+  node_type:
+    type: string
+  key_name:
+    type: string
+    description: Name of keypair to assign to servers
+  image:
+    type: string
+    description: Name of image to use for servers
+  flavor:
+    type: string
+    description: Flavor to use for servers
+  control_network:
+    type: string
+  control_subnet_id:
+    type: string
+  private_floating_network:
+    type: string
+  private_floating_network_cidr:
+    type: string
+  private_floating_subnet_id:
+    type: string
+  private_floating_interface:
+    type: string
+  control_network_cidr:
+    type: string
+  functions_override:
+    type: string
+    default: ''
+  boot_timeout:
+    type: number
+    description: Boot timeout for instance
+    default: 3600
+  ucp_master_host:
+    type: string
+    default: ''
+  public_net_id:
+    type: string
+  docker_ee_release:
+    type: string
+  docker_ee_url:
+    type: string
+  docker_ucp_image:
+    type: string
+    default: 'docker/ucp:3.2.4'
+  hardware_metadata:
+    description: The content of lab metadata.
+    default: ''
+    type: string
+
+resources:
+
+  software_config:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: ungrouped
+      config:
+        str_replace:
+          template: { get_file: ../../scripts/instance_boot.sh }
+          params:
+            $node_type:  { get_param: node_type }
+            $wait_condition_notify: { get_attr: [ wait_handle, curl_cli ] }
+            $docker_ee_url: { get_param: docker_ee_url }
+            $docker_ee_release: { get_param: docker_ee_release }
+            $ucp_master_host: { get_param: ucp_master_host }
+            $docker_ucp_image: { get_param: docker_ucp_image }
+            $node_metadata: { get_param: metadata }
+            $control_network_cidr: { get_param: control_network_cidr }
+            $private_floating_interface: { get_param: private_floating_interface }
+            $private_floating_interface_ip: { get_attr: [private_floating_server_port, fixed_ips, 0, ip_address] }
+            $private_floating_network_cidr: { get_param: private_floating_network_cidr }
+            $functions_override: { get_param: functions_override }
+            $docker_ucp_image: { get_param: docker_ucp_image }
+
+  inject_files:
+    type: "OS::Heat::CloudConfig"
+    properties:
+      cloud_config:
+        write_files:
+          - path: /usr/sbin/prepare-metadata.py
+            owner: "root:root"
+            permissions: "0755"
+            content: {get_file: ../../scripts/prepare-metadata.py}
+          - path: /usr/share/metadata/lab-metadata.yaml
+            owner: "root:root"
+            permissions: "0644"
+            content: { get_param: hardware_metadata}
+
+  install_config_agent:
+    type: "OS::Heat::MultipartMime"
+    properties:
+      parts:
+      - config: {get_resource: software_config}
+      - config: {get_resource: inject_files}
+
+  server:
+    type: OS::Nova::Server
+    properties:
+      image: { get_param: image }
+      flavor: { get_param: flavor }
+      key_name: { get_param: key_name }
+      availability_zone: nova
+      networks:
+        - port: { get_resource: control_server_port }
+        - port: { get_resource: private_floating_server_port }
+      user_data_format: SOFTWARE_CONFIG
+      user_data: { get_resource:  install_config_agent}
+      metadata: { get_param: metadata }
+
+  control_server_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_param: control_network }
+      port_security_enabled: false
+      fixed_ips:
+        - subnet: { get_param: control_subnet_id }
+
+  private_floating_server_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_param: private_floating_network }
+      port_security_enabled: false
+      fixed_ips:
+        - subnet: { get_param: private_floating_subnet_id }
+
+  server_floating_ip:
+    type: OS::Neutron::FloatingIP
+    properties:
+      floating_network_id: { get_param: public_net_id }
+      port_id: { get_resource: control_server_port }
+
+  wait_handle:
+    type: OS::Heat::WaitConditionHandle
+  wait_condition:
+    type: OS::Heat::WaitCondition
+    properties:
+      handle: { get_resource: wait_handle }
+      timeout: { get_param: boot_timeout }
+
+outputs:
+  server_control_ip:
+    description: IP address of server in private network
+    value: { get_attr: [server, networks, { get_param: control_network}, 0]}
+  server_public_ip:
+    description: Floating IP address of server in public network
+    value: { get_attr: [ server_floating_ip, floating_ip_address ] }
+  wc_data:
+    description: Metadata from instance
+    value: { get_attr: [wait_condition, data]}
diff --git a/de/heat-templates/fragments/multirack/SrvInstancesVMCeph.yaml b/de/heat-templates/fragments/multirack/SrvInstancesVMCeph.yaml
new file mode 100644
index 0000000..79373ed
--- /dev/null
+++ b/de/heat-templates/fragments/multirack/SrvInstancesVMCeph.yaml
@@ -0,0 +1,154 @@
+heat_template_version: queens
+
+parameters:
+
+  metadata:
+    type: json
+    default: {}
+  node_type:
+    type: string
+  key_name:
+    type: string
+    description: Name of keypair to assign to servers
+  image:
+    type: string
+    description: Name of image to use for servers
+  flavor:
+    type: string
+    description: Flavor to use for servers
+  control_network:
+    type: string
+  control_subnet_id:
+    type: string
+  private_floating_network:
+    type: string
+  private_floating_network_cidr:
+    type: string
+  private_floating_subnet_id:
+    type: string
+  private_floating_interface:
+    type: string
+  control_network_cidr:
+    type: string
+  functions_override:
+    type: string
+    default: ''
+  boot_timeout:
+    type: number
+    description: Boot timeout for instance
+    default: 3600
+  ucp_master_host:
+    type: string
+  public_net_id:
+    type: string
+  docker_ee_release:
+    type: string
+  docker_ee_url:
+    type: string
+  docker_ucp_image:
+    type: string
+    default: 'docker/ucp:3.2.4'
+  hardware_metadata:
+    description: The content of lab metadata.
+    default: ''
+    type: string
+
+resources:
+
+  software_config:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: ungrouped
+      config:
+        str_replace:
+          template: { get_file: ../../scripts/instance_boot.sh }
+          params:
+            $node_type:  { get_param: node_type }
+            $wait_condition_notify: { get_attr: [ wait_handle, curl_cli ] }
+            $docker_ee_url: { get_param: docker_ee_url }
+            $docker_ee_release: { get_param: docker_ee_release }
+            $ucp_master_host: { get_param: ucp_master_host }
+            $docker_ucp_image: { get_param: docker_ucp_image }
+            $node_metadata: { get_param: metadata }
+            $control_network_cidr: { get_param: control_network_cidr }
+            $private_floating_interface: { get_param: private_floating_interface }
+            $private_floating_interface_ip: { get_attr: [private_floating_server_port, fixed_ips, 0, ip_address] }
+            $private_floating_network_cidr: { get_param: private_floating_network_cidr }
+            $functions_override: { get_param: functions_override }
+            $docker_ucp_image: { get_param: docker_ucp_image }
+
+  inject_files:
+    type: "OS::Heat::CloudConfig"
+    properties:
+      cloud_config:
+        write_files:
+          - path: /usr/sbin/prepare-metadata.py
+            owner: "root:root"
+            permissions: "0755"
+            content: {get_file: ../../scripts/prepare-metadata.py}
+          - path: /usr/share/metadata/lab-metadata.yaml
+            owner: "root:root"
+            permissions: "0644"
+            content: { get_param: hardware_metadata}
+
+  install_config_agent:
+    type: "OS::Heat::MultipartMime"
+    properties:
+      parts:
+      - config: {get_resource: software_config}
+      - config: {get_resource: inject_files}
+
+  server:
+    type: OS::Nova::Server
+    properties:
+      image: { get_param: image }
+      flavor: { get_param: flavor }
+      key_name: { get_param: key_name }
+      availability_zone: nova
+      networks:
+        - port: { get_resource: control_server_port }
+        - port: { get_resource: private_floating_server_port }
+      user_data_format: SOFTWARE_CONFIG
+      user_data: { get_resource:  install_config_agent}
+      metadata: { get_param: metadata }
+
+  control_server_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_param: control_network }
+      port_security_enabled: false
+      fixed_ips:
+        - subnet: { get_param: control_subnet_id }
+
+  private_floating_server_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_param: private_floating_network }
+      port_security_enabled: false
+      fixed_ips:
+        - subnet: { get_param: private_floating_subnet_id }
+
+  server_floating_ip:
+    type: OS::Neutron::FloatingIP
+    properties:
+      floating_network_id: { get_param: public_net_id }
+      port_id: { get_resource: control_server_port }
+
+  wait_handle:
+    type: OS::Heat::WaitConditionHandle
+  wait_condition:
+    type: OS::Heat::WaitCondition
+    properties:
+      handle: { get_resource: wait_handle }
+      timeout: { get_param: boot_timeout }
+
+outputs:
+  server_control_ip:
+    description: IP address of server in private network
+    value: { get_attr: [server, networks, { get_param: control_network}, 0]}
+  server_public_ip:
+    description: Floating IP address of server in public network
+    value: { get_attr: [ server_floating_ip, floating_ip_address ] }
+  wc_data:
+    description: Metadata from instance
+    value: { get_attr: [wait_condition, data]}
diff --git a/de/heat-templates/fragments/multirack/SrvInstancesVMRack.yaml b/de/heat-templates/fragments/multirack/SrvInstancesVMRack.yaml
new file mode 100644
index 0000000..a27610d
--- /dev/null
+++ b/de/heat-templates/fragments/multirack/SrvInstancesVMRack.yaml
@@ -0,0 +1,135 @@
+heat_template_version: queens
+
+parameters:
+
+  metadata:
+    type: json
+    default: {}
+  node_type:
+    type: string
+  key_name:
+    type: string
+    description: Name of keypair to assign to servers
+  image:
+    type: string
+    description: Name of image to use for servers
+  flavor:
+    type: string
+    description: Flavor to use for servers
+  control_network:
+    type: string
+  control_subnet_id:
+    type: string
+  control_network_cidr:
+    type: string
+  functions_override:
+    type: string
+    default: ''
+  boot_timeout:
+    type: number
+    description: Boot timeout for instance
+    default: 3600
+  ucp_master_host:
+    type: string
+    default: ''
+  public_net_id:
+    type: string
+  docker_ee_release:
+    type: string
+  docker_ee_url:
+    type: string
+  docker_ucp_image:
+    type: string
+    default: 'docker/ucp:3.2.4'
+  hardware_metadata:
+    description: The content of lab metadata.
+    default: ''
+    type: string
+
+resources:
+
+  software_config:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: ungrouped
+      config:
+        str_replace:
+          template: { get_file: ../../scripts/instance_boot.sh }
+          params:
+            $node_type:  { get_param: node_type }
+            $wait_condition_notify: { get_attr: [ wait_handle, curl_cli ] }
+            $docker_ee_url: { get_param: docker_ee_url }
+            $docker_ee_release: { get_param: docker_ee_release }
+            $ucp_master_host: { get_param: ucp_master_host }
+            $docker_ucp_image: { get_param: docker_ucp_image }
+            $node_metadata: { get_param: metadata }
+            $control_network_cidr: { get_param: control_network_cidr }
+            $docker_ucp_image: { get_param: docker_ucp_image }
+            $functions_override: { get_param: functions_override }
+
+  inject_files:
+    type: "OS::Heat::CloudConfig"
+    properties:
+      cloud_config:
+        write_files:
+          - path: /usr/sbin/prepare-metadata.py
+            owner: "root:root"
+            permissions: "0755"
+            content: {get_file: ../../scripts/prepare-metadata.py}
+          - path: /usr/share/metadata/lab-metadata.yaml
+            owner: "root:root"
+            permissions: "0644"
+            content: { get_param: hardware_metadata}
+
+  install_config_agent:
+    type: "OS::Heat::MultipartMime"
+    properties:
+      parts:
+      - config: {get_resource: software_config}
+      - config: {get_resource: inject_files}
+
+  server:
+    type: OS::Nova::Server
+    properties:
+      image: { get_param: image }
+      flavor: { get_param: flavor }
+      key_name: { get_param: key_name }
+      availability_zone: nova
+      networks:
+        - port: { get_resource: control_server_port }
+      user_data_format: SOFTWARE_CONFIG
+      user_data: { get_resource:  install_config_agent}
+      metadata: { get_param: metadata }
+
+  control_server_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_param: control_network }
+      port_security_enabled: false
+      fixed_ips:
+        - subnet: { get_param: control_subnet_id }
+
+  server_floating_ip:
+    type: OS::Neutron::FloatingIP
+    properties:
+      floating_network_id: { get_param: public_net_id }
+      port_id: { get_resource: control_server_port }
+
+  wait_handle:
+    type: OS::Heat::WaitConditionHandle
+  wait_condition:
+    type: OS::Heat::WaitCondition
+    properties:
+      handle: { get_resource: wait_handle }
+      timeout: { get_param: boot_timeout }
+
+outputs:
+  server_control_ip:
+    description: IP address of server in private network
+    value: { get_attr: [server, networks, { get_param: control_network}, 0]}
+  server_public_ip:
+    description: Floating IP address of server in public network
+    value: { get_attr: [ server_floating_ip, floating_ip_address ] }
+  wc_data:
+    description: Metadata from instance
+    value: { get_attr: [wait_condition, data]}
diff --git a/de/heat-templates/multirack.yaml b/de/heat-templates/multirack.yaml
new file mode 100644
index 0000000..6886747
--- /dev/null
+++ b/de/heat-templates/multirack.yaml
@@ -0,0 +1,218 @@
+heat_template_version: queens
+
+parameters:
+  image:
+    type: string
+    description: Name of image to use for servers
+  public_net_id:
+    type: string
+    default: ''
+    description: >
+      ID of public network for which floating IP addresses will be allocated/
+      for baremetal case flat provision network for nodes
+  lab_network_cidr:
+    type: string
+    default: '10.0.0.0/8'
+  main_network_cidr:
+    type: string
+    default: '10.0.0.0/16'
+  main_control_network_cidr:
+    type: string
+    description: The CIDR of control network, used to detect control interface.
+    default: '10.0.1.0/24'
+  main_tunnel_network_cidr:
+    type: string
+    default: '10.0.2.0/24'
+  main_storage_frontend_network_cidr:
+    type: string
+    default: '10.0.3.0/24'
+  main_storage_backend_network_cidr:
+    type: string
+    default: '10.0.4.0/24'
+  main_private_floating_network_cidr:
+    type: string
+    default: '10.0.5.0/24'
+  main_private_floating_network_interface:
+    type: string
+    default: 'ens4'
+  rack01_network_cidr:
+    type: string
+    default: '10.1.0.0/16'
+  rack01_control_network_cidr:
+    type: string
+    description: The CIDR of control network, used to detect control interface.
+    default: '10.1.1.0/24'
+  rack01_central_router_uplink_network_cidr:
+    type: string
+    default: '192.168.0.0/28'
+  rack02_network_cidr:
+    type: string
+    default: '10.2.0.0/16'
+  rack02_control_network_cidr:
+    type: string
+    description: The CIDR of control network, used to detect control interface.
+    default: '10.2.1.0/24'
+  rack02_central_router_uplink_network_cidr:
+    type: string
+    default: '192.168.0.16/28'
+  main_worker_size:
+    type: number
+    description: Number of workers to deploy
+    default: 3
+  rack01_cmp_size:
+    type: number
+    description: Number of cmp workers to deploy
+    default: 0
+  rack02_cmp_size:
+    type: number
+    description: Number of cmp workers to deploy
+    default: 0
+  cluster_public_key:
+    type: string
+  ucp_metadata:
+    type: json
+    default: {"role":"ucp"}
+  main_worker_metadata:
+    type: json
+    default: {}
+  rack01_cmp_metadata:
+    type: json
+    default: {}
+  rack02_cmp_metadata:
+    type: json
+    default: {}
+  ucp_flavor:
+    type: string
+    default: 'kaas-bm.worker'
+  main_worker_flavor:
+    type: string
+    default: 'system.compact.openstack.control'
+  rack01_cmp_flavor:
+    type: string
+    default: 'system.compact.openstack.control'
+  rack02_cmp_flavor:
+    type: string
+    default: 'system.compact.openstack.control'
+  docker_ee_url:
+    type: string
+    default: 'http://mirror-us.mcp.mirantis.net/.snapshots/docker-ee-bionic-latest'
+#    default: 'https://s3-us-west-2.amazonaws.com/internal-docker-ee-builds/docker-ee-linux/ubuntu'
+  docker_ee_release:
+    type: string
+    default: 'stable-19.03'
+  docker_ucp_image:
+    type: string
+    default: 'docker/ucp:3.2.4'
+  tunnel_interface:
+    type: string
+    default: ''
+  main_worker_hardware_metadata:
+    type: string
+    default: ''
+
+resources:
+  keypair_name:
+    type: OS::Heat::RandomString
+    properties:
+      character_classes: [{"class": "hexdigits", "min": 1}]
+      length: 128
+      salt: constant
+  key_pair:
+    type: OS::Nova::KeyPair
+    properties:
+      name: { get_attr: [keypair_name, value] }
+      public_key: { get_param: cluster_public_key }
+      save_private_key: false
+
+  central_site:
+    type: MCP2::CentralSite
+    properties:
+      ucp_metadata: { get_param: ucp_metadata}
+      docker_ee_url: { get_param: docker_ee_url }
+      docker_ee_release: { get_param: docker_ee_release }
+      docker_ucp_image: { get_param: docker_ucp_image}
+      key_name: { get_attr: [keypair_name, value] }
+      image: { get_param: image }
+      ucp_flavor: { get_param: ucp_flavor }
+      public_net_id: { get_param: public_net_id }
+      control_network_cidr: { get_param: main_control_network_cidr }
+      tunnel_network_cidr: { get_param: main_tunnel_network_cidr }
+      storage_frontend_network_cidr: { get_param: main_storage_frontend_network_cidr }
+      storage_backend_network_cidr: { get_param: main_storage_backend_network_cidr }
+      private_floating_network_cidr: { get_param: main_private_floating_network_cidr }
+      private_floating_network_interface: { get_param: main_private_floating_network_interface }
+      worker_size: { get_param: main_worker_size }
+      worker_flavor: { get_param: main_worker_flavor }
+      worker_metadata: { get_param: main_worker_metadata }
+      worker_hardware_metadata: { get_param: main_worker_hardware_metadata }
+
+  rack01_router_routes:
+    type: MCP2::RackRouterRoutes
+    properties:
+      central_router: { get_attr: [central_site, router_id] }
+      central_router_uplink_network_cidr: { get_param: rack01_central_router_uplink_network_cidr }
+      site_cidr: { get_param: rack01_network_cidr }
+      lab_network_cidr: { get_param: lab_network_cidr }
+      public_net_id: { get_param: public_net_id }
+
+  rack01:
+    depends_on:
+    - central_site
+    type: MCP2::Rack
+    properties:
+      docker_ee_url: { get_param: docker_ee_url }
+      docker_ee_release: { get_param: docker_ee_release }
+      docker_ucp_image: { get_param: docker_ucp_image}
+      key_name: { get_attr: [keypair_name, value] }
+      image: { get_param: image }
+      public_net_id: { get_param: public_net_id }
+      control_network_cidr: { get_param: rack01_control_network_cidr }
+      cmp_size: { get_param: rack01_cmp_size }
+      cmp_flavor: { get_param: rack01_cmp_flavor }
+      cmp_metadata: { get_param: rack01_cmp_metadata }
+      ucp_master_host: { get_attr: [central_site, ucp_control_ip] }
+      rack_router: {get_attr: [rack01_router_routes, router_id] }
+
+  rack02_router_routes:
+    depends_on:
+    - rack01_router_routes
+    type: MCP2::RackRouterRoutes
+    properties:
+      central_router: { get_attr: [central_site, router_id] }
+      central_router_uplink_network_cidr: { get_param: rack02_central_router_uplink_network_cidr }
+      site_cidr: { get_param: rack02_network_cidr }
+      lab_network_cidr: { get_param: lab_network_cidr }
+      public_net_id: { get_param: public_net_id }
+
+  rack02:
+    depends_on:
+    - central_site
+    type: MCP2::Rack
+    properties:
+      docker_ee_url: { get_param: docker_ee_url }
+      docker_ee_release: { get_param: docker_ee_release }
+      docker_ucp_image: { get_param: docker_ucp_image}
+      key_name: { get_attr: [keypair_name, value] }
+      image: { get_param: image }
+      public_net_id: { get_param: public_net_id }
+      control_network_cidr: { get_param: rack02_control_network_cidr }
+      cmp_size: { get_param: rack02_cmp_size }
+      cmp_flavor: { get_param: rack02_cmp_flavor }
+      cmp_metadata: { get_param: rack02_cmp_metadata }
+      ucp_master_host: { get_attr: [central_site, ucp_control_ip] }
+      rack_router: {get_attr: [rack02_router_routes, router_id] }
+
+outputs:
+  central_site_worker_public_ip:
+    description: IP address of server in private network
+    value: { get_attr: [central_site, worker_public_ip] }
+  ucp_public_ip:
+    description: IP address of server in private network
+    value: { get_attr: [central_site, ucp_public_ip] }
+  central_site_worker_wc_data:
+    description: Metadata from instance
+    value: { get_attr: [central_site, worker_wc_data]}
+  rack01_cmp_public_ip:
+    value: { get_attr: [rack01, cmp_public_ip] }
+  rack02_cmp_public_ip:
+    value: { get_attr: [rack02, cmp_public_ip] }