CVP Shaker docker repo

Change-Id: If9d39409caaf4eb562ca6734a26808642b4ffd3b
Related-task: https://mirantis.jira.com/browse/PROD-24883
diff --git a/Dockerfile b/Dockerfile
index 3557ef2..f8368ed 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,29 +1,13 @@
-FROM perfoma/shaker:1.2.0
+FROM performa/shaker:1.2.0
 
-LABEL maintainer="Oleg Basov <obasov@mirantis.com>" version="1.0"
+LABEL maintainer="dev@mirantis.com" MAINTENANCE_VERSION=2019-02-08
 
 RUN apt-get update && \
     DEBIAN_FRONTEND=noninteractive apt upgrade -yq && \
-    DEBIAN_FRONTEND=noninteractive apt install -yq sudo qemu-utils kpartx sudo squashfs-tools \
-        python3 python3-dev python3-pip python3-venv python3-tk wget
+    DEBIAN_FRONTEND=noninteractive apt install -yq sudo \
+    qemu-utils kpartx squashfs-tools
 
-#COPY . /opt/shaker
+COPY bin /usr/local/bin/
+COPY scenarios /opt/shaker/scenarios
 
-# git clone https://github.com/Mirantis/disk_perf_test_tool.git /opt/disk_perf_tool
-
-#RUN git clone https://github.com/koder-ua/cephlib.git /opt/cephlib && \
-#    git clone https://github.com/koder-ua/xmlbuilder3.git /opt/xmlbuilder3 && \
-#    git clone https://github.com/koder-ua/agent.git /opt/agent && \
-#    python3.6 -m pip install pip --upgrade && \
-#    cd /opt/wally && \
-#    python3.6 -m pip install wheel && \
-#    python3.6 -m pip install -r requirements.txt && \
-#    python3.6 -m pip install -U cryptography && \
-#    ln -s /opt/wally/scripts/shaker /usr/bin && \
-#    chmod a+x /opt/wally/scripts/wally
-
-#RUN apt purge -y python3-dev build-essential && apt -y autoremove
-
-#ENV PYTHONPATH /opt/cephlib:/opt/xmlbuilder3:/opt/agent:/opt/
-
-CMD ["/bin/bash"]
+ENTRYPOINT ["entrypoint.sh"]
diff --git a/bin/entrypoint.sh b/bin/entrypoint.sh
new file mode 100755
index 0000000..daba3d4
--- /dev/null
+++ b/bin/entrypoint.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+set -xe
+exec "$@"
diff --git a/scenarios/additional/cross_az/full_l2.yaml b/scenarios/additional/cross_az/full_l2.yaml
new file mode 100644
index 0000000..49e25e3
--- /dev/null
+++ b/scenarios/additional/cross_az/full_l2.yaml
@@ -0,0 +1,28 @@
+title: OpenStack L2 Cross-AZ
+
+description:
+  In this scenario Shaker launches pairs of instances in the same tenant
+  network. Every instance is hosted on a separate compute node, all available
+  compute nodes are utilized. The master and slave instances are in different
+  availability zones. The scenario is used to test throughput between `nova`
+  and `vcenter` zones. The traffic goes within the tenant network (L2 domain).
+
+deployment:
+  template: l2.hot
+  accommodation: [pair, single_room, zones: [nova, vcenter], cross_az]
+
+execution:
+  progression: quadratic
+  tests:
+  -
+    title: Download
+    class: flent
+    method: tcp_download
+  -
+    title: Upload
+    class: flent
+    method: tcp_upload
+  -
+    title: Bi-directional
+    class: flent
+    method: tcp_bidirectional
diff --git a/scenarios/additional/cross_az/full_l3_east_west.yaml b/scenarios/additional/cross_az/full_l3_east_west.yaml
new file mode 100644
index 0000000..227787b
--- /dev/null
+++ b/scenarios/additional/cross_az/full_l3_east_west.yaml
@@ -0,0 +1,29 @@
+title: OpenStack L3 East-West Cross-AZ
+
+description:
+  In this scenario Shaker launches pairs of instances, each instance on its own
+  compute node. All available compute nodes are utilized. Instances are
+  connected to one of 2 tenant networks, which plugged into single router.
+  The traffic goes from one network to the other (L3 east-west).
+  The master and slave instances are in different availability zones.
+  The scenario is used to test throughput between `nova` and `vcenter` zones.
+
+deployment:
+  template: l3_east_west.hot
+  accommodation: [pair, single_room, zones: [nova, vcenter], cross_az]
+
+execution:
+  progression: quadratic
+  tests:
+  -
+    title: Download
+    class: flent
+    method: tcp_download
+  -
+    title: Upload
+    class: flent
+    method: tcp_upload
+  -
+    title: Bi-directional
+    class: flent
+    method: tcp_bidirectional
diff --git a/scenarios/additional/cross_az/full_l3_north_south.yaml b/scenarios/additional/cross_az/full_l3_north_south.yaml
new file mode 100644
index 0000000..fdcb11f
--- /dev/null
+++ b/scenarios/additional/cross_az/full_l3_north_south.yaml
@@ -0,0 +1,30 @@
+title: OpenStack L3 North-South Cross-AZ
+
+description:
+  In this scenario Shaker launches pairs of instances on different compute
+  nodes. All available compute nodes are utilized. Instances are in different
+  networks connected to different routers, master accesses slave by
+  floating ip. The traffic goes from one network via external network to the
+  other network. The master and slave instances are in different availability
+  zones. The scenario is used to test throughput between `nova` and `vcenter`
+  zones.
+
+deployment:
+  template: l3_north_south.hot
+  accommodation: [pair, single_room, zones: [nova, vcenter], cross_az]
+
+execution:
+  progression: quadratic
+  tests:
+  -
+    title: Download
+    class: flent
+    method: tcp_download
+  -
+    title: Upload
+    class: flent
+    method: tcp_upload
+  -
+    title: Bi-directional
+    class: flent
+    method: tcp_bidirectional
diff --git a/scenarios/additional/cross_az/l2.hot b/scenarios/additional/cross_az/l2.hot
new file mode 100644
index 0000000..349f68a
--- /dev/null
+++ b/scenarios/additional/cross_az/l2.hot
@@ -0,0 +1,102 @@
+heat_template_version: 2013-05-23
+
+description:
+  This Heat template creates a new Neutron network, a router to the external
+  network and plugs instances into this new network. All instances are located
+  in the same L2 domain.
+
+parameters:
+  image:
+    type: string
+    description: Name of image to use for servers
+  flavor:
+    type: string
+    description: Flavor to use for servers
+  external_net:
+    type: string
+    description: ID or name of external network
+  server_endpoint:
+    type: string
+    description: Server endpoint address
+  dns_nameservers:
+    type: comma_delimited_list
+    description: DNS nameservers for the subnet
+
+resources:
+  private_net:
+    type: OS::Neutron::Net
+    properties:
+      name: {{ unique }}_net
+
+  private_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network_id: { get_resource: private_net }
+      cidr: 10.0.0.0/16
+      dns_nameservers: { get_param: dns_nameservers }
+
+  router:
+    type: OS::Neutron::Router
+    properties:
+      external_gateway_info:
+        network: { get_param: external_net }
+
+  router_interface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router_id: { get_resource: router }
+      subnet_id: { get_resource: private_subnet }
+
+  server_security_group:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      rules: [
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: tcp,
+        port_range_min: 1,
+        port_range_max: 65535},
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: udp,
+        port_range_min: 1,
+        port_range_max: 65535},
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: icmp}]
+
+{% for agent in agents.values() %}
+
+  {{ agent.id }}:
+    type: OS::Nova::Server
+    properties:
+      name: {{ agent.id }}
+      image: {% if agent.zone == 'vcenter' %} shaker-image-vcenter {% else %} shaker-image-nova {% endif %}
+      flavor: { get_param: flavor }
+      availability_zone: "{{ agent.availability_zone }}"
+      networks:
+        - port: { get_resource: {{ agent.id }}_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          template: |
+            #!/bin/sh
+            screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
+          params:
+            "$SERVER_ENDPOINT": { get_param: server_endpoint }
+            "$AGENT_ID": {{ agent.id }}
+
+  {{ agent.id }}_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_resource: private_net }
+      fixed_ips:
+        - subnet_id: { get_resource: private_subnet }
+      security_groups: [{ get_resource: server_security_group }]
+
+{% endfor %}
+
+outputs:
+{% for agent in agents.values() %}
+  {{ agent.id }}_instance_name:
+    value: { get_attr: [ {{ agent.id }}, instance_name ] }
+  {{ agent.id }}_ip:
+    value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [private_net, name] }, 0 ] }
+{% endfor %}
diff --git a/scenarios/additional/cross_az/l3_east_west.hot b/scenarios/additional/cross_az/l3_east_west.hot
new file mode 100644
index 0000000..2bcfede
--- /dev/null
+++ b/scenarios/additional/cross_az/l3_east_west.hot
@@ -0,0 +1,134 @@
+heat_template_version: 2013-05-23
+
+description:
+  This Heat template creates a pair of networks plugged into the same router.
+  Master instances and slave instances are connected into different networks.
+
+parameters:
+  image:
+    type: string
+    description: Name of image to use for servers
+  flavor:
+    type: string
+    description: Flavor to use for servers
+  external_net:
+    type: string
+    description: ID or name of external network for which floating IP addresses will be allocated
+  server_endpoint:
+    type: string
+    description: Server endpoint address
+  dns_nameservers:
+    type: comma_delimited_list
+    description: DNS nameservers for the subnets
+
+resources:
+  east_private_net:
+    type: OS::Neutron::Net
+    properties:
+      name: {{ unique }}_net_east
+
+  east_private_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network_id: { get_resource: east_private_net }
+      cidr: 10.1.0.0/16
+      dns_nameservers: { get_param: dns_nameservers }
+
+  router:
+    type: OS::Neutron::Router
+    properties:
+      external_gateway_info:
+        network: { get_param: external_net }
+
+  router_interface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router_id: { get_resource: router }
+      subnet_id: { get_resource: east_private_subnet }
+
+  west_private_net:
+    type: OS::Neutron::Net
+    properties:
+      name: {{ unique }}_net_west
+
+  west_private_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network_id: { get_resource: west_private_net }
+      cidr: 10.2.0.0/16
+      dns_nameservers: { get_param: dns_nameservers }
+
+  router_interface_2:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router_id: { get_resource: router }
+      subnet_id: { get_resource: west_private_subnet }
+
+  server_security_group:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      rules: [
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: tcp,
+        port_range_min: 1,
+        port_range_max: 65535},
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: udp,
+        port_range_min: 1,
+        port_range_max: 65535},
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: icmp}]
+
+{% for agent in agents.values() %}
+
+  {{ agent.id }}:
+    type: OS::Nova::Server
+    properties:
+      name: {{ agent.id }}
+      image: {% if agent.zone == 'vcenter' %} shaker-image-vcenter {% else %} shaker-image-nova {% endif %}
+      flavor: { get_param: flavor }
+      availability_zone: "{{ agent.availability_zone }}"
+      networks:
+        - port: { get_resource: {{ agent.id }}_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          template: |
+            #!/bin/sh
+            screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
+          params:
+            "$SERVER_ENDPOINT": { get_param: server_endpoint }
+            "$AGENT_ID": {{ agent.id }}
+
+{% if agent.mode == 'master' %}
+  {{ agent.id }}_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_resource: east_private_net }
+      fixed_ips:
+        - subnet_id: { get_resource: east_private_subnet }
+      security_groups: [{ get_resource: server_security_group }]
+{% else %}
+  {{ agent.id }}_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_resource: west_private_net }
+      fixed_ips:
+        - subnet_id: { get_resource: west_private_subnet }
+      security_groups: [{ get_resource: server_security_group }]
+{% endif %}
+
+{% endfor %}
+
+outputs:
+{% for agent in agents.values() %}
+  {{ agent.id }}_instance_name:
+    value: { get_attr: [ {{ agent.id }}, instance_name ] }
+{% if agent.mode == 'master' %}
+  {{ agent.id }}_ip:
+    value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [east_private_net, name] }, 0 ] }
+{% else %}
+  {{ agent.id }}_ip:
+    value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [west_private_net, name] }, 0 ] }
+{% endif %}
+{% endfor %}
diff --git a/scenarios/additional/cross_az/l3_north_south.hot b/scenarios/additional/cross_az/l3_north_south.hot
new file mode 100644
index 0000000..76ffa6c
--- /dev/null
+++ b/scenarios/additional/cross_az/l3_north_south.hot
@@ -0,0 +1,148 @@
+heat_template_version: 2013-05-23
+
+description: >
+  This Heat template creates a new Neutron network plus a north_router to the
+  external network. The template also assigns floating IP addresses to each
+  instance so they are routable from the external network.
+
+parameters:
+  image:
+    type: string
+    description: Name of image to use for servers
+  flavor:
+    type: string
+    description: Flavor to use for servers
+  external_net:
+    type: string
+    description: ID or name of external network for which floating IP addresses will be allocated
+  server_endpoint:
+    type: string
+    description: Server endpoint address
+  dns_nameservers:
+    type: comma_delimited_list
+    description: DNS nameservers for the subnets
+
+resources:
+  north_private_net:
+    type: OS::Neutron::Net
+    properties:
+      name: {{ unique }}_net_north
+
+  north_private_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network_id: { get_resource: north_private_net }
+      cidr: 10.1.0.0/16
+      dns_nameservers: { get_param: dns_nameservers }
+
+  north_router:
+    type: OS::Neutron::Router
+    properties:
+      external_gateway_info:
+        network: { get_param: external_net }
+
+  router_interface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router_id: { get_resource: north_router }
+      subnet_id: { get_resource: north_private_subnet }
+
+  south_private_net:
+    type: OS::Neutron::Net
+    properties:
+      name: {{ unique }}_net_south
+
+  south_private_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network_id: { get_resource: south_private_net }
+      cidr: 10.2.0.0/16
+      dns_nameservers: { get_param: dns_nameservers }
+
+  south_router:
+    type: OS::Neutron::Router
+    properties:
+      external_gateway_info:
+        network: { get_param: external_net }
+
+  router_interface_2:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router_id: { get_resource: south_router }
+      subnet_id: { get_resource: south_private_subnet }
+
+  server_security_group:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      rules: [
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: tcp,
+        port_range_min: 1,
+        port_range_max: 65535},
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: udp,
+        port_range_min: 1,
+        port_range_max: 65535},
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: icmp}]
+
+{% for agent in agents.values() %}
+
+  {{ agent.id }}:
+    type: OS::Nova::Server
+    properties:
+      name: {{ agent.id }}
+      image: {% if agent.zone == 'vcenter' %} shaker-image-vcenter {% else %} shaker-image-nova {% endif %}
+      flavor: { get_param: flavor }
+      availability_zone: "{{ agent.availability_zone }}"
+      networks:
+        - port: { get_resource: {{ agent.id }}_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          template: |
+            #!/bin/sh
+            screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
+          params:
+            "$SERVER_ENDPOINT": { get_param: server_endpoint }
+            "$AGENT_ID": {{ agent.id }}
+
+{% if agent.mode == 'master' %}
+  {{ agent.id }}_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_resource: north_private_net }
+      fixed_ips:
+        - subnet_id: { get_resource: north_private_subnet }
+      security_groups: [{ get_resource: server_security_group }]
+{% else %}
+  {{ agent.id }}_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_resource: south_private_net }
+      fixed_ips:
+        - subnet_id: { get_resource: south_private_subnet }
+      security_groups: [{ get_resource: server_security_group }]
+
+  {{ agent.id }}_floating_ip:
+    type: OS::Neutron::FloatingIP
+    depends_on: router_interface_2
+    properties:
+      floating_network: { get_param: external_net }
+      port_id: { get_resource: {{ agent.id }}_port }
+{% endif %}
+
+{% endfor %}
+
+outputs:
+{% for agent in agents.values() %}
+  {{ agent.id }}_instance_name:
+    value: { get_attr: [ {{ agent.id }}, instance_name ] }
+{% if agent.mode == 'master' %}
+  {{ agent.id }}_ip:
+    value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [north_private_net, name] }, 0 ] }
+{% else %}
+  {{ agent.id }}_ip:
+    value: { get_attr: [ {{ agent.id }}_floating_ip, floating_ip_address ] }
+{% endif %}
+{% endfor %}
diff --git a/scenarios/additional/cross_az/perf_l2.yaml b/scenarios/additional/cross_az/perf_l2.yaml
new file mode 100644
index 0000000..6c53394
--- /dev/null
+++ b/scenarios/additional/cross_az/perf_l2.yaml
@@ -0,0 +1,35 @@
+title: OpenStack L2 Cross-AZ Performance
+
+description:
+  In this scenario Shaker launches 1 pair of instances in the same tenant
+  network. Each instance is hosted on a separate compute node.
+  The master and slave instances are in different availability zones.
+  The scenario is used to test throughput between `nova` and `vcenter` zones.
+
+deployment:
+  template: l2.hot
+  accommodation: [pair, single_room, zones: [nova, vcenter], cross_az, compute_nodes: 2]
+
+execution:
+  tests:
+  -
+    title: Ping
+    class: flent
+    method: ping
+    time: 10
+    sla:
+    - "[type == 'agent'] >> (stats.ping_icmp.avg < 2.0)"
+  -
+    title: TCP
+    class: iperf3
+    sla:
+    - "[type == 'agent'] >> (stats.bandwidth.avg > 5000)"
+    - "[type == 'agent'] >> (stats.retransmits.max < 10)"
+  -
+    title: UDP
+    class: iperf3
+    udp: on
+    bandwidth: 0
+    datagram_size: 32
+    sla:
+    - "[type == 'agent'] >> (stats.packets.avg > 100000)"
diff --git a/scenarios/additional/cross_az/perf_l3_east_west.yaml b/scenarios/additional/cross_az/perf_l3_east_west.yaml
new file mode 100644
index 0000000..606b172
--- /dev/null
+++ b/scenarios/additional/cross_az/perf_l3_east_west.yaml
@@ -0,0 +1,37 @@
+title: OpenStack L3 East-West Cross-AZ Performance
+
+description:
+  In this scenario Shaker launches 1 pair of instances, each instance on its own
+  compute node. Instances are connected to one of 2 tenant networks, which
+  plugged into single router. The traffic goes from one network to the other
+  (L3 east-west).
+  The master and slave instances are in different availability zones.
+  The scenario is used to test throughput between `nova` and `vcenter` zones.
+
+deployment:
+  template: l3_east_west.hot
+  accommodation: [pair, single_room, zones: [nova, vcenter], cross_az, compute_nodes: 2]
+
+execution:
+  tests:
+  -
+    title: Ping
+    class: flent
+    method: ping
+    time: 10
+    sla:
+    - "[type == 'agent'] >> (stats.ping_icmp.avg < 2.0)"
+  -
+    title: TCP
+    class: iperf3
+    sla:
+    - "[type == 'agent'] >> (stats.bandwidth.avg > 5000)"
+    - "[type == 'agent'] >> (stats.retransmits.max < 10)"
+  -
+    title: UDP
+    class: iperf3
+    udp: on
+    bandwidth: 0
+    datagram_size: 32
+    sla:
+    - "[type == 'agent'] >> (stats.packets.avg > 100000)"
diff --git a/scenarios/additional/cross_az/perf_l3_north_south.yaml b/scenarios/additional/cross_az/perf_l3_north_south.yaml
new file mode 100644
index 0000000..5f9a1fd
--- /dev/null
+++ b/scenarios/additional/cross_az/perf_l3_north_south.yaml
@@ -0,0 +1,37 @@
+title: OpenStack L3 North-South Cross-AZ Performance
+
+description:
+  In this scenario Shaker launches 1 pair of instances on different compute
+  nodes. Instances are in different networks connected to different routers,
+  master accesses slave by floating ip. The traffic goes from one network
+  via external network to the other network.
+  The master and slave instances are in different availability zones.
+  The scenario is used to test throughput between `nova` and `vcenter` zones.
+
+deployment:
+  template: l3_north_south.hot
+  accommodation: [pair, single_room, zones: [nova, vcenter], cross_az, compute_nodes: 2]
+
+execution:
+  tests:
+  -
+    title: Ping
+    class: flent
+    method: ping
+    time: 10
+    sla:
+    - "[type == 'agent'] >> (stats.ping_icmp.avg < 2.0)"
+  -
+    title: TCP
+    class: iperf3
+    sla:
+    - "[type == 'agent'] >> (stats.bandwidth.avg > 5000)"
+    - "[type == 'agent'] >> (stats.retransmits.max < 10)"
+  -
+    title: UDP
+    class: iperf3
+    udp: on
+    bandwidth: 0
+    datagram_size: 32
+    sla:
+    - "[type == 'agent'] >> (stats.packets.avg > 100000)"
diff --git a/scenarios/additional/cross_az/udp_l2.yaml b/scenarios/additional/cross_az/udp_l2.yaml
new file mode 100644
index 0000000..058db75
--- /dev/null
+++ b/scenarios/additional/cross_az/udp_l2.yaml
@@ -0,0 +1,22 @@
+title: OpenStack L2 Cross-AZ UDP
+
+description:
+  In this scenario Shaker launches pairs of instances in the same tenant
+  network. Every instance is hosted on a separate compute node.
+  The load is generated by UDP traffic.
+  The master and slave instances are in different availability zones.
+  The scenario is used to test throughput between `nova` and `vcenter` zones.
+
+deployment:
+  template: l2.hot
+  accommodation: [pair, single_room, zones: [nova, vcenter], cross_az]
+
+execution:
+  progression: quadratic
+  tests:
+  -
+    title: UDP
+    class: iperf3
+    udp: on
+    bandwidth: 1000M
+    datagram_size: 32
diff --git a/scenarios/additional/cross_az/udp_l2_mss8950.yaml b/scenarios/additional/cross_az/udp_l2_mss8950.yaml
new file mode 100644
index 0000000..9866e94
--- /dev/null
+++ b/scenarios/additional/cross_az/udp_l2_mss8950.yaml
@@ -0,0 +1,23 @@
+title: OpenStack L2 Cross-AZ UDP Jumbo
+
+description:
+  In this scenario Shaker launches pairs of instances in the same tenant
+  network. Every instance is hosted on a separate compute node.
+  The load is generated by UDP traffic and jumbo packets.
+  The master and slave instances are in different availability zones.
+  The scenario is used to test throughput between `nova` and `vcenter` zones.
+
+deployment:
+  template: l2.hot
+  accommodation: [pair, single_room, zones: [nova, vcenter], cross_az]
+
+execution:
+  progression: quadratic
+  tests:
+  -
+    title: UDP
+    class: iperf
+    udp: 1
+    threads: 2
+    bandwidth: 1000M
+    buffer_size: 8950
diff --git a/scenarios/additional/cross_az/udp_l3_east_west.yaml b/scenarios/additional/cross_az/udp_l3_east_west.yaml
new file mode 100644
index 0000000..647abbc
--- /dev/null
+++ b/scenarios/additional/cross_az/udp_l3_east_west.yaml
@@ -0,0 +1,23 @@
+title: OpenStack L3 East-West Cross-AZ UDP
+
+description:
+  In this scenario Shaker launches pairs of instances, each instance on its own
+  compute node. Instances are connected to one of 2 tenant networks, which
+  plugged into single router. The traffic goes from one network to the other
+  (L3 east-west). The load is generated by UDP traffic.
+  The master and slave instances are in different availability zones.
+  The scenario is used to test throughput between `nova` and `vcenter` zones.
+
+deployment:
+  template: l3_east_west.hot
+  accommodation: [pair, single_room, zones: [nova, vcenter], cross_az]
+
+execution:
+  progression: quadratic
+  tests:
+  -
+    title: UDP
+    class: iperf3
+    udp: on
+    bandwidth: 1000M
+    datagram_size: 32
diff --git a/scenarios/additional/external/dense_l3_north_south_no_fip.yaml b/scenarios/additional/external/dense_l3_north_south_no_fip.yaml
new file mode 100644
index 0000000..73a4124
--- /dev/null
+++ b/scenarios/additional/external/dense_l3_north_south_no_fip.yaml
@@ -0,0 +1,27 @@
+title: OpenStack L3 North-South Dense to external target
+
+description: >
+  In this scenario Shaker launches instances on one compute node in a tenant
+  network connected to external network. The traffic is sent to and from
+  external host. The host name needs to be provided as command-line parameter,
+  e.g. ``--matrix "{host: 172.10.1.2}"``.
+
+deployment:
+  template: l3_north_south_no_fip.hot
+  accommodation: [double_room, density: 8, compute_nodes: 1]
+
+execution:
+  progression: linear
+  tests:
+  -
+    title: Download
+    class: flent
+    method: tcp_download
+  -
+    title: Upload
+    class: flent
+    method: tcp_upload
+  -
+    title: Bi-directional
+    class: flent
+    method: tcp_bidirectional
diff --git a/scenarios/additional/external/dense_l3_north_south_with_fip.yaml b/scenarios/additional/external/dense_l3_north_south_with_fip.yaml
new file mode 100644
index 0000000..bb66a28
--- /dev/null
+++ b/scenarios/additional/external/dense_l3_north_south_with_fip.yaml
@@ -0,0 +1,27 @@
+title: OpenStack L3 North-South Dense to external target with floating IP
+
+description: >
+  In this scenario Shaker launches instances on one compute node in a tenant
+  network connected to external network. All instances have floating IPs.
+  The traffic is sent to and from external host. The host name needs to be
+  provided as command-line parameter, e.g. ``--matrix "{host: 172.10.1.2}"``.
+
+deployment:
+  template: l3_north_south_with_fip.hot
+  accommodation: [double_room, density: 8, compute_nodes: 1]
+
+execution:
+  progression: linear
+  tests:
+  -
+    title: Download
+    class: flent
+    method: tcp_download
+  -
+    title: Upload
+    class: flent
+    method: tcp_upload
+  -
+    title: Bi-directional
+    class: flent
+    method: tcp_bidirectional
diff --git a/scenarios/additional/external/full_l3_north_south_no_fip.yaml b/scenarios/additional/external/full_l3_north_south_no_fip.yaml
new file mode 100644
index 0000000..ff172b6
--- /dev/null
+++ b/scenarios/additional/external/full_l3_north_south_no_fip.yaml
@@ -0,0 +1,28 @@
+title: OpenStack L3 North-South to external target
+
+description: >
+  In this scenario Shaker launches instances in a tenant network connected
+  to external network. Every instance is hosted on dedicated compute node.
+  All available compute nodes are utilized. The traffic is sent to and
+  from external host (L3 north-south). The host name needs to be provided as
+  command-line parameter, e.g. ``--matrix "{host: 172.10.1.2}"``.
+
+deployment:
+  template: l3_north_south_no_fip.hot
+  accommodation: [single_room]
+
+execution:
+  progression: quadratic
+  tests:
+  -
+    title: Download
+    class: flent
+    method: tcp_download
+  -
+    title: Upload
+    class: flent
+    method: tcp_upload
+  -
+    title: Bi-directional
+    class: flent
+    method: tcp_bidirectional
diff --git a/scenarios/additional/external/full_l3_north_south_with_fip.yaml b/scenarios/additional/external/full_l3_north_south_with_fip.yaml
new file mode 100644
index 0000000..b7d3b6a
--- /dev/null
+++ b/scenarios/additional/external/full_l3_north_south_with_fip.yaml
@@ -0,0 +1,29 @@
+title: OpenStack L3 North-South to external target with floating IP
+
+description: >
+  In this scenario Shaker launches instances in a tenant network connected
+  to external network. Every instance is hosted on dedicated compute node.
+  All available compute nodes are utilized. All instances have floating IPs.
+  The traffic is sent to and from external host (L3 north-south). The host
+  name needs to be provided as command-line parameter, e.g.
+  ``--matrix "{host: 172.10.1.2}"``.
+
+deployment:
+  template: l3_north_south_with_fip.hot
+  accommodation: [single_room]
+
+execution:
+  progression: quadratic
+  tests:
+  -
+    title: Download
+    class: flent
+    method: tcp_download
+  -
+    title: Upload
+    class: flent
+    method: tcp_upload
+  -
+    title: Bi-directional
+    class: flent
+    method: tcp_bidirectional
diff --git a/scenarios/additional/external/l3_north_south_no_fip.hot b/scenarios/additional/external/l3_north_south_no_fip.hot
new file mode 100644
index 0000000..94b1dad
--- /dev/null
+++ b/scenarios/additional/external/l3_north_south_no_fip.hot
@@ -0,0 +1,85 @@
+heat_template_version: 2013-05-23
+
+description: >
+  This Heat template creates a new Neutron network plugged into a router
+  connected to the external network, and boots an instance in that network.
+
+parameters:
+  image:
+    type: string
+    description: Name of image to use for servers
+  flavor:
+    type: string
+    description: Flavor to use for servers
+  external_net:
+    type: string
+    description: ID or name of external network for which floating IP addresses will be allocated
+  server_endpoint:
+    type: string
+    description: Server endpoint address
+  dns_nameservers:
+    type: comma_delimited_list
+    description: DNS nameservers for the subnets
+
+resources:
+  north_private_net:
+    type: OS::Neutron::Net
+    properties:
+      name: {{ unique }}_net_north
+
+  north_private_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network_id: { get_resource: north_private_net }
+      cidr: 10.1.0.0/16
+      dns_nameservers: { get_param: dns_nameservers }
+
+  north_router:
+    type: OS::Neutron::Router
+    properties:
+      external_gateway_info:
+        network: { get_param: external_net }
+
+  router_interface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router_id: { get_resource: north_router }
+      subnet_id: { get_resource: north_private_subnet }
+
+{% for agent in agents.values() %}
+
+  {{ agent.id }}:
+    type: OS::Nova::Server
+    properties:
+      name: {{ agent.id }}
+      image: { get_param: image }
+      flavor: { get_param: flavor }
+      availability_zone: "{{ agent.availability_zone }}"
+      networks:
+        - port: { get_resource: {{ agent.id }}_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          template: |
+            #!/bin/sh
+            screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
+          params:
+            "$SERVER_ENDPOINT": { get_param: server_endpoint }
+            "$AGENT_ID": {{ agent.id }}
+
+  {{ agent.id }}_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_resource: north_private_net }
+      fixed_ips:
+        - subnet_id: { get_resource: north_private_subnet }
+
+{% endfor %}
+
+outputs:
+{% for agent in agents.values() %}
+  {{ agent.id }}_instance_name:
+    value: { get_attr: [ {{ agent.id }}, instance_name ] }
+  {{ agent.id }}_ip:
+    value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [north_private_net, name] }, 0 ] }
+{% endfor %}
diff --git a/scenarios/additional/external/l3_north_south_with_fip.hot b/scenarios/additional/external/l3_north_south_with_fip.hot
new file mode 100644
index 0000000..89039d8
--- /dev/null
+++ b/scenarios/additional/external/l3_north_south_with_fip.hot
@@ -0,0 +1,93 @@
+heat_template_version: 2013-05-23
+
+description: >
+  This Heat template creates a new Neutron network plugged into a router
+  connected to the external network, and boots an instance in that network.
+  The instance has floating IP.
+
+parameters:
+  image:
+    type: string
+    description: Name of image to use for servers
+  flavor:
+    type: string
+    description: Flavor to use for servers
+  external_net:
+    type: string
+    description: ID or name of external network for which floating IP addresses will be allocated
+  server_endpoint:
+    type: string
+    description: Server endpoint address
+  dns_nameservers:
+    type: comma_delimited_list
+    description: DNS nameservers for the subnets
+
+resources:
+  north_private_net:
+    type: OS::Neutron::Net
+    properties:
+      name: {{ unique }}_net_north
+
+  north_private_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network_id: { get_resource: north_private_net }
+      cidr: 10.1.0.0/16
+      dns_nameservers: { get_param: dns_nameservers }
+
+  north_router:
+    type: OS::Neutron::Router
+    properties:
+      external_gateway_info:
+        network: { get_param: external_net }
+
+  router_interface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router_id: { get_resource: north_router }
+      subnet_id: { get_resource: north_private_subnet }
+
+{% for agent in agents.values() %}
+
+  {{ agent.id }}:
+    type: OS::Nova::Server
+    properties:
+      name: {{ agent.id }}
+      image: { get_param: image }
+      flavor: { get_param: flavor }
+      availability_zone: "{{ agent.availability_zone }}"
+      networks:
+        - port: { get_resource: {{ agent.id }}_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          template: |
+            #!/bin/sh
+            screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
+          params:
+            "$SERVER_ENDPOINT": { get_param: server_endpoint }
+            "$AGENT_ID": {{ agent.id }}
+
+  {{ agent.id }}_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_resource: north_private_net }
+      fixed_ips:
+        - subnet_id: { get_resource: north_private_subnet }
+
+  {{ agent.id }}_floating_ip:
+    type: OS::Neutron::FloatingIP
+    depends_on: router_interface
+    properties:
+      floating_network: { get_param: external_net }
+      port_id: { get_resource: {{ agent.id }}_port }
+
+{% endfor %}
+
+outputs:
+{% for agent in agents.values() %}
+  {{ agent.id }}_instance_name:
+    value: { get_attr: [ {{ agent.id }}, instance_name ] }
+  {{ agent.id }}_ip:
+    value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [north_private_net, name] }, 0 ] }
+{% endfor %}
diff --git a/scenarios/additional/external/perf_l3_north_south_no_fip.yaml b/scenarios/additional/external/perf_l3_north_south_no_fip.yaml
new file mode 100644
index 0000000..ff9e2c1
--- /dev/null
+++ b/scenarios/additional/external/perf_l3_north_south_no_fip.yaml
@@ -0,0 +1,57 @@
+title: OpenStack L3 North-South Performance to external target
+
+description: >
+  In this scenario Shaker launches instance in a tenant network connected
+  to external network. The traffic is sent to and from external host.
+  By default one of public iperf3 servers is used, to override this the target
+  host can be provided as command-line parameter,
+  e.g. ``--matrix "{host: 172.10.1.2}"``.
+
+deployment:
+  template: l3_north_south_no_fip.hot
+  accommodation: [single_room, compute_nodes: 1]
+
+execution:
+  tests:
+  -
+    title: Ping
+    class: flent
+    host: ikoula.testdebit.info
+    method: ping
+    time: 10
+    sla:
+    - "[type == 'agent'] >> (stats.ping_icmp.avg < 2.0)"
+  -
+    title: TCP egress
+    class: iperf3
+    host: ikoula.testdebit.info
+    sla:
+    - "[type == 'agent'] >> (stats.bandwidth.avg > 5000)"
+    - "[type == 'agent'] >> (stats.retransmits.max < 10)"
+  -
+    title: TCP ingress
+    class: iperf3
+    host: ikoula.testdebit.info
+    reverse: yes
+    sla:
+    - "[type == 'agent'] >> (stats.bandwidth.avg > 5000)"
+    - "[type == 'agent'] >> (stats.retransmits.max < 10)"
+  -
+    title: UDP egress
+    class: iperf3
+    host: ikoula.testdebit.info
+    udp: on
+    bandwidth: 0
+    datagram_size: 32
+    sla:
+    - "[type == 'agent'] >> (stats.packets.avg > 100000)"
+  -
+    title: UDP ingress
+    class: iperf3
+    host: ikoula.testdebit.info
+    reverse: yes
+    udp: on
+    bandwidth: 0
+    datagram_size: 32
+    sla:
+    - "[type == 'agent'] >> (stats.packets.avg > 100000)"
diff --git a/scenarios/additional/external/perf_l3_north_south_with_fip.yaml b/scenarios/additional/external/perf_l3_north_south_with_fip.yaml
new file mode 100644
index 0000000..1aa60ef
--- /dev/null
+++ b/scenarios/additional/external/perf_l3_north_south_with_fip.yaml
@@ -0,0 +1,57 @@
+title: OpenStack L3 North-South performance to external target with floating IP
+
+description: >
+  In this scenario Shaker launches instance in a tenant network connected
+  to external network. The instance has floating IP. The traffic is sent to
+  and from external host. By default one of public iperf3 servers is used,
+  to override this the target host can be provided as command-line parameter,
+  e.g. ``--matrix "{host: 172.10.1.2}"``.
+
+deployment:
+  template: l3_north_south_with_fip.hot
+  accommodation: [single_room, compute_nodes: 1]
+
+execution:
+  tests:
+  -
+    title: Ping
+    class: flent
+    host: ikoula.testdebit.info
+    method: ping
+    time: 10
+    sla:
+    - "[type == 'agent'] >> (stats.ping_icmp.avg < 2.0)"
+  -
+    title: TCP egress
+    class: iperf3
+    host: ikoula.testdebit.info
+    sla:
+    - "[type == 'agent'] >> (stats.bandwidth.avg > 5000)"
+    - "[type == 'agent'] >> (stats.retransmits.max < 10)"
+  -
+    title: TCP ingress
+    class: iperf3
+    host: ikoula.testdebit.info
+    reverse: yes
+    sla:
+    - "[type == 'agent'] >> (stats.bandwidth.avg > 5000)"
+    - "[type == 'agent'] >> (stats.retransmits.max < 10)"
+  -
+    title: UDP egress
+    class: iperf3
+    host: ikoula.testdebit.info
+    udp: on
+    bandwidth: 0
+    datagram_size: 32
+    sla:
+    - "[type == 'agent'] >> (stats.packets.avg > 100000)"
+  -
+    title: UDP ingress
+    class: iperf3
+    host: ikoula.testdebit.info
+    reverse: yes
+    udp: on
+    bandwidth: 0
+    datagram_size: 32
+    sla:
+    - "[type == 'agent'] >> (stats.packets.avg > 100000)"
diff --git a/scenarios/additional/qos/l2_qos.hot b/scenarios/additional/qos/l2_qos.hot
new file mode 100644
index 0000000..c3cbe1b
--- /dev/null
+++ b/scenarios/additional/qos/l2_qos.hot
@@ -0,0 +1,113 @@
+heat_template_version: 2013-05-23
+
+description:
+  This Heat template creates a new Neutron network, a router to the external
+  network and plugs instances into this new network. All instances are located
+  in the same L2 domain.
+
+parameters:
+  image:
+    type: string
+    description: Name of image to use for servers
+  flavor:
+    type: string
+    description: Flavor to use for servers
+  external_net:
+    type: string
+    description: ID or name of external network
+  server_endpoint:
+    type: string
+    description: Server endpoint address
+  dns_nameservers:
+    type: comma_delimited_list
+    description: DNS nameservers for the subnet
+
+resources:
+  qos_policy:
+    type: OS::Neutron::QoSPolicy
+
+  bandwidth_limit_rule:
+    type: OS::Neutron::QoSBandwidthLimitRule
+    properties:
+      policy: { get_resource: qos_policy }
+      max_kbps: 10000
+      max_burst_kbps: 10000
+
+  private_net:
+    type: OS::Neutron::Net
+    properties:
+      name: {{ unique }}_net
+      qos_policy: { get_resource: qos_policy }
+
+  private_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network_id: { get_resource: private_net }
+      cidr: 10.0.0.0/16
+      dns_nameservers: { get_param: dns_nameservers }
+
+  router:
+    type: OS::Neutron::Router
+    properties:
+      external_gateway_info:
+        network: { get_param: external_net }
+
+  router_interface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router_id: { get_resource: router }
+      subnet_id: { get_resource: private_subnet }
+
+  server_security_group:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      rules: [
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: tcp,
+        port_range_min: 1,
+        port_range_max: 65535},
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: udp,
+        port_range_min: 1,
+        port_range_max: 65535},
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: icmp}]
+
+{% for agent in agents.values() %}
+
+  {{ agent.id }}:
+    type: OS::Nova::Server
+    properties:
+      name: {{ agent.id }}
+      image: { get_param: image }
+      flavor: { get_param: flavor }
+      availability_zone: "{{ agent.availability_zone }}"
+      networks:
+        - port: { get_resource: {{ agent.id }}_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          template: |
+            #!/bin/sh
+            screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
+          params:
+            "$SERVER_ENDPOINT": { get_param: server_endpoint }
+            "$AGENT_ID": {{ agent.id }}
+
+  {{ agent.id }}_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_resource: private_net }
+      fixed_ips:
+        - subnet_id: { get_resource: private_subnet }
+      security_groups: [{ get_resource: server_security_group }]
+
+{% endfor %}
+
+outputs:
+{% for agent in agents.values() %}
+  {{ agent.id }}_instance_name:
+    value: { get_attr: [ {{ agent.id }}, instance_name ] }
+  {{ agent.id }}_ip:
+    value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [private_net, name] }, 0 ] }
+{% endfor %}
diff --git a/scenarios/additional/qos/perf_l2.yaml b/scenarios/additional/qos/perf_l2.yaml
new file mode 100644
index 0000000..b634693
--- /dev/null
+++ b/scenarios/additional/qos/perf_l2.yaml
@@ -0,0 +1,34 @@
+title: OpenStack L2 QoS Performance
+
+description:
+  In this scenario Shaker launches 1 pair of instances in the same tenant
+  network. Each instance is hosted on a separate compute node. The traffic goes
+  within the tenant network (L2 domain). Neutron QoS feature is used to limit
+  traffic throughput to 10 Mbit/s.
+
+deployment:
+  template: l2_qos.hot
+  accommodation: [pair, single_room, compute_nodes: 2]
+
+execution:
+  tests:
+  -
+    title: Ping
+    class: flent
+    method: ping
+    time: 10
+    sla:
+    - "[type == 'agent'] >> (stats.ping_icmp.avg < 2.0)"
+  -
+    title: TCP
+    class: iperf3
+    sla:
+    - "[type == 'agent'] >> (stats.bandwidth.avg < 11)"
+  -
+    title: UDP
+    class: iperf3
+    udp: on
+    bandwidth: 0
+    datagram_size: 32
+    sla:
+    - "[type == 'agent'] >> (stats.packets.avg * (100 - stats.loss.avg) / 100 < 40000)"
diff --git a/scenarios/essential/l2/dense_l2.yaml b/scenarios/essential/l2/dense_l2.yaml
new file mode 100644
index 0000000..6347a17
--- /dev/null
+++ b/scenarios/essential/l2/dense_l2.yaml
@@ -0,0 +1,26 @@
+title: OpenStack L2 Dense
+
+description:
+  In this scenario Shaker launches several pairs of instances on a single
+  compute node. Instances are plugged into the same tenant network.
+  The traffic goes within the tenant network (L2 domain).
+
+deployment:
+  template: l2.hot
+  accommodation: [pair, double_room, density: 6, compute_nodes: 1]
+
+execution:
+  progression: linear
+  tests:
+  -
+    title: Download
+    class: flent
+    method: tcp_download
+  -
+    title: Upload
+    class: flent
+    method: tcp_upload
+  -
+    title: Bi-directional
+    class: flent
+    method: tcp_bidirectional
diff --git a/scenarios/essential/l2/full_l2.yaml b/scenarios/essential/l2/full_l2.yaml
new file mode 100644
index 0000000..9767a26
--- /dev/null
+++ b/scenarios/essential/l2/full_l2.yaml
@@ -0,0 +1,27 @@
+title: OpenStack L2
+
+description:
+  In this scenario Shaker launches pairs of instances in the same tenant
+  network. Every instance is hosted on a separate compute node, all available
+  compute nodes are utilized. The traffic goes within the tenant network
+  (L2 domain).
+
+deployment:
+  template: l2.hot
+  accommodation: [pair, single_room]
+
+execution:
+  progression: quadratic
+  tests:
+  -
+    title: Download
+    class: flent
+    method: tcp_download
+  -
+    title: Upload
+    class: flent
+    method: tcp_upload
+  -
+    title: Bi-directional
+    class: flent
+    method: tcp_bidirectional
diff --git a/scenarios/essential/l2/l2.hot b/scenarios/essential/l2/l2.hot
new file mode 100644
index 0000000..3636a49
--- /dev/null
+++ b/scenarios/essential/l2/l2.hot
@@ -0,0 +1,102 @@
+heat_template_version: 2013-05-23
+
+description:
+  This Heat template creates a new Neutron network, a router to the external
+  network and plugs instances into this new network. All instances are located
+  in the same L2 domain.
+
+parameters:
+  image:
+    type: string
+    description: Name of image to use for servers
+  flavor:
+    type: string
+    description: Flavor to use for servers
+  external_net:
+    type: string
+    description: ID or name of external network
+  server_endpoint:
+    type: string
+    description: Server endpoint address
+  dns_nameservers:
+    type: comma_delimited_list
+    description: DNS nameservers for the subnet
+
+resources:
+  private_net:
+    type: OS::Neutron::Net
+    properties:
+      name: {{ unique }}_net
+
+  private_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network_id: { get_resource: private_net }
+      cidr: 10.0.0.0/16
+      dns_nameservers: { get_param: dns_nameservers }
+
+  router:
+    type: OS::Neutron::Router
+    properties:
+      external_gateway_info:
+        network: { get_param: external_net }
+
+  router_interface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router_id: { get_resource: router }
+      subnet_id: { get_resource: private_subnet }
+
+  server_security_group:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      rules: [
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: tcp,
+        port_range_min: 1,
+        port_range_max: 65535},
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: udp,
+        port_range_min: 1,
+        port_range_max: 65535},
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: icmp}]
+
+{% for agent in agents.values() %}
+
+  {{ agent.id }}:
+    type: OS::Nova::Server
+    properties:
+      name: {{ agent.id }}
+      image: { get_param: image }
+      flavor: { get_param: flavor }
+      availability_zone: "{{ agent.availability_zone }}"
+      networks:
+        - port: { get_resource: {{ agent.id }}_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          template: |
+            #!/bin/sh
+            screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
+          params:
+            "$SERVER_ENDPOINT": { get_param: server_endpoint }
+            "$AGENT_ID": {{ agent.id }}
+
+  {{ agent.id }}_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_resource: private_net }
+      fixed_ips:
+        - subnet_id: { get_resource: private_subnet }
+      security_groups: [{ get_resource: server_security_group }]
+
+{% endfor %}
+
+outputs:
+{% for agent in agents.values() %}
+  {{ agent.id }}_instance_name:
+    value: { get_attr: [ {{ agent.id }}, instance_name ] }
+  {{ agent.id }}_ip:
+    value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [private_net, name] }, 0 ] }
+{% endfor %}
diff --git a/scenarios/essential/l2/perf_l2.yaml b/scenarios/essential/l2/perf_l2.yaml
new file mode 100644
index 0000000..a38ef31
--- /dev/null
+++ b/scenarios/essential/l2/perf_l2.yaml
@@ -0,0 +1,34 @@
+title: OpenStack L2 Performance
+
+description:
+  In this scenario Shaker launches 1 pair of instances in the same tenant
+  network. Each instance is hosted on a separate compute node. The traffic goes
+  within the tenant network (L2 domain).
+
+deployment:
+  template: l2.hot
+  accommodation: [pair, single_room, compute_nodes: 2]
+
+execution:
+  tests:
+  -
+    title: Ping
+    class: flent
+    method: ping
+    time: 10
+    sla:
+    - "[type == 'agent'] >> (stats.ping_icmp.avg < 2.0)"
+  -
+    title: TCP
+    class: iperf3
+    sla:
+    - "[type == 'agent'] >> (stats.bandwidth.avg > 5000)"
+    - "[type == 'agent'] >> (stats.retransmits.max < 10)"
+  -
+    title: UDP
+    class: iperf3
+    udp: on
+    bandwidth: 0
+    datagram_size: 32
+    sla:
+    - "[type == 'agent'] >> (stats.packets.avg > 100000)"
diff --git a/scenarios/essential/l2/udp_l2.yaml b/scenarios/essential/l2/udp_l2.yaml
new file mode 100644
index 0000000..0e142e5
--- /dev/null
+++ b/scenarios/essential/l2/udp_l2.yaml
@@ -0,0 +1,21 @@
+title: OpenStack L2 UDP
+
+description:
+  In this scenario Shaker launches pairs of instances in the same tenant
+  network. Every instance is hosted on a separate compute node.
+  The traffic goes within the tenant network (L2 domain). The load is
+  generated by UDP traffic.
+
+deployment:
+  template: l2.hot
+  accommodation: [pair, single_room]
+
+execution:
+  progression: quadratic
+  tests:
+  -
+    title: UDP
+    class: iperf3
+    udp: on
+    bandwidth: 1000M
+    datagram_size: 32
diff --git a/scenarios/essential/l3/dense_l3_east_west.yaml b/scenarios/essential/l3/dense_l3_east_west.yaml
new file mode 100644
index 0000000..44c3457
--- /dev/null
+++ b/scenarios/essential/l3/dense_l3_east_west.yaml
@@ -0,0 +1,26 @@
+title: OpenStack L3 East-West Dense
+
+description:
+  In this scenario Shaker launches pairs of instances on the same compute node.
+  Instances are connected to different tenant networks connected to one
+  router. The traffic goes from one network to the other (L3 east-west).
+
+deployment:
+  template: l3_east_west.hot
+  accommodation: [pair, double_room, density: 8, compute_nodes: 1]
+
+execution:
+  progression: linear
+  tests:
+  -
+    title: Download
+    class: flent
+    method: tcp_download
+  -
+    title: Upload
+    class: flent
+    method: tcp_upload
+  -
+    title: Bi-directional
+    class: flent
+    method: tcp_bidirectional
diff --git a/scenarios/essential/l3/dense_l3_north_south.yaml b/scenarios/essential/l3/dense_l3_north_south.yaml
new file mode 100644
index 0000000..1b91182
--- /dev/null
+++ b/scenarios/essential/l3/dense_l3_north_south.yaml
@@ -0,0 +1,27 @@
+title: OpenStack L3 North-South Dense
+
+description:
+  In this scenario Shaker launches pairs of instances on the same compute node.
+  Instances are connected to different tenant networks, each connected to own
+  router. Instances in one of networks have floating IPs.
+  The traffic goes from one network via external network to the other network.
+
+deployment:
+  template: l3_north_south.hot
+  accommodation: [pair, double_room, density: 8, compute_nodes: 1]
+
+execution:
+  progression: linear
+  tests:
+  -
+    title: Download
+    class: flent
+    method: tcp_download
+  -
+    title: Upload
+    class: flent
+    method: tcp_upload
+  -
+    title: Bi-directional
+    class: flent
+    method: tcp_bidirectional
diff --git a/scenarios/essential/l3/full_l3_east_west.yaml b/scenarios/essential/l3/full_l3_east_west.yaml
new file mode 100644
index 0000000..2e10877
--- /dev/null
+++ b/scenarios/essential/l3/full_l3_east_west.yaml
@@ -0,0 +1,27 @@
+title: OpenStack L3 East-West
+
+description:
+  In this scenario Shaker launches pairs of instances, each instance on its own
+  compute node. All available compute nodes are utilized. Instances are
+  connected to one of 2 tenant networks, which plugged into single router.
+  The traffic goes from one network to the other (L3 east-west).
+
+deployment:
+  template: l3_east_west.hot
+  accommodation: [pair, single_room]
+
+execution:
+  progression: quadratic
+  tests:
+  -
+    title: Download
+    class: flent
+    method: tcp_download
+  -
+    title: Upload
+    class: flent
+    method: tcp_upload
+  -
+    title: Bi-directional
+    class: flent
+    method: tcp_bidirectional
diff --git a/scenarios/essential/l3/full_l3_north_south.yaml b/scenarios/essential/l3/full_l3_north_south.yaml
new file mode 100644
index 0000000..ee20773
--- /dev/null
+++ b/scenarios/essential/l3/full_l3_north_south.yaml
@@ -0,0 +1,28 @@
+title: OpenStack L3 North-South
+
+description:
+  In this scenario Shaker launches pairs of instances on different compute
+  nodes. All available compute nodes are utilized. Instances are in different
+  networks connected to different routers, master accesses slave by
+  floating ip. The traffic goes from one network via external network to
+  the other network.
+
+deployment:
+  template: l3_north_south.hot
+  accommodation: [pair, single_room]
+
+execution:
+  progression: quadratic
+  tests:
+  -
+    title: Download
+    class: flent
+    method: tcp_download
+  -
+    title: Upload
+    class: flent
+    method: tcp_upload
+  -
+    title: Bi-directional
+    class: flent
+    method: tcp_bidirectional
diff --git a/scenarios/essential/l3/l3_east_west.hot b/scenarios/essential/l3/l3_east_west.hot
new file mode 100644
index 0000000..5b90b2d
--- /dev/null
+++ b/scenarios/essential/l3/l3_east_west.hot
@@ -0,0 +1,134 @@
+heat_template_version: 2013-05-23
+
+description:
+  This Heat template creates a pair of networks plugged into the same router.
+  Master instances and slave instances are connected into different networks.
+
+parameters:
+  image:
+    type: string
+    description: Name of image to use for servers
+  flavor:
+    type: string
+    description: Flavor to use for servers
+  external_net:
+    type: string
+    description: ID or name of external network for which floating IP addresses will be allocated
+  server_endpoint:
+    type: string
+    description: Server endpoint address
+  dns_nameservers:
+    type: comma_delimited_list
+    description: DNS nameservers for the subnets
+
+resources:
+  east_private_net:
+    type: OS::Neutron::Net
+    properties:
+      name: {{ unique }}_net_east
+
+  east_private_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network_id: { get_resource: east_private_net }
+      cidr: 10.1.0.0/16
+      dns_nameservers: { get_param: dns_nameservers }
+
+  router:
+    type: OS::Neutron::Router
+    properties:
+      external_gateway_info:
+        network: { get_param: external_net }
+
+  router_interface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router_id: { get_resource: router }
+      subnet_id: { get_resource: east_private_subnet }
+
+  west_private_net:
+    type: OS::Neutron::Net
+    properties:
+      name: {{ unique }}_net_west
+
+  west_private_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network_id: { get_resource: west_private_net }
+      cidr: 10.2.0.0/16
+      dns_nameservers: { get_param: dns_nameservers }
+
+  router_interface_2:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router_id: { get_resource: router }
+      subnet_id: { get_resource: west_private_subnet }
+
+  server_security_group:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      rules: [
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: tcp,
+        port_range_min: 1,
+        port_range_max: 65535},
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: udp,
+        port_range_min: 1,
+        port_range_max: 65535},
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: icmp}]
+
+{% for agent in agents.values() %}
+
+  {{ agent.id }}:
+    type: OS::Nova::Server
+    properties:
+      name: {{ agent.id }}
+      image: { get_param: image }
+      flavor: { get_param: flavor }
+      availability_zone: "{{ agent.availability_zone }}"
+      networks:
+        - port: { get_resource: {{ agent.id }}_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          template: |
+            #!/bin/sh
+            screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
+          params:
+            "$SERVER_ENDPOINT": { get_param: server_endpoint }
+            "$AGENT_ID": {{ agent.id }}
+
+{% if agent.mode == 'master' %}
+  {{ agent.id }}_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_resource: east_private_net }
+      fixed_ips:
+        - subnet_id: { get_resource: east_private_subnet }
+      security_groups: [{ get_resource: server_security_group }]
+{% else %}
+  {{ agent.id }}_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_resource: west_private_net }
+      fixed_ips:
+        - subnet_id: { get_resource: west_private_subnet }
+      security_groups: [{ get_resource: server_security_group }]
+{% endif %}
+
+{% endfor %}
+
+outputs:
+{% for agent in agents.values() %}
+  {{ agent.id }}_instance_name:
+    value: { get_attr: [ {{ agent.id }}, instance_name ] }
+{% if agent.mode == 'master' %}
+  {{ agent.id }}_ip:
+    value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [east_private_net, name] }, 0 ] }
+{% else %}
+  {{ agent.id }}_ip:
+    value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [west_private_net, name] }, 0 ] }
+{% endif %}
+{% endfor %}
diff --git a/scenarios/essential/l3/l3_north_south.hot b/scenarios/essential/l3/l3_north_south.hot
new file mode 100644
index 0000000..06b4b56
--- /dev/null
+++ b/scenarios/essential/l3/l3_north_south.hot
@@ -0,0 +1,148 @@
+heat_template_version: 2013-05-23
+
+description: >
+  This Heat template creates a new Neutron network plus a north_router to the
+  external network. The template also assigns floating IP addresses to each
+  instance so they are routable from the external network.
+
+parameters:
+  image:
+    type: string
+    description: Name of image to use for servers
+  flavor:
+    type: string
+    description: Flavor to use for servers
+  external_net:
+    type: string
+    description: ID or name of external network for which floating IP addresses will be allocated
+  server_endpoint:
+    type: string
+    description: Server endpoint address
+  dns_nameservers:
+    type: comma_delimited_list
+    description: DNS nameservers for the subnets
+
+resources:
+  north_private_net:
+    type: OS::Neutron::Net
+    properties:
+      name: {{ unique }}_net_north
+
+  north_private_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network_id: { get_resource: north_private_net }
+      cidr: 10.1.0.0/16
+      dns_nameservers: { get_param: dns_nameservers }
+
+  north_router:
+    type: OS::Neutron::Router
+    properties:
+      external_gateway_info:
+        network: { get_param: external_net }
+
+  router_interface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router_id: { get_resource: north_router }
+      subnet_id: { get_resource: north_private_subnet }
+
+  south_private_net:
+    type: OS::Neutron::Net
+    properties:
+      name: {{ unique }}_net_south
+
+  south_private_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      network_id: { get_resource: south_private_net }
+      cidr: 10.2.0.0/16
+      dns_nameservers: { get_param: dns_nameservers }
+
+  south_router:
+    type: OS::Neutron::Router
+    properties:
+      external_gateway_info:
+        network: { get_param: external_net }
+
+  router_interface_2:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router_id: { get_resource: south_router }
+      subnet_id: { get_resource: south_private_subnet }
+
+  server_security_group:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      rules: [
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: tcp,
+        port_range_min: 1,
+        port_range_max: 65535},
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: udp,
+        port_range_min: 1,
+        port_range_max: 65535},
+        {remote_ip_prefix: 0.0.0.0/0,
+        protocol: icmp}]
+
+{% for agent in agents.values() %}
+
+  {{ agent.id }}:
+    type: OS::Nova::Server
+    properties:
+      name: {{ agent.id }}
+      image: { get_param: image }
+      flavor: { get_param: flavor }
+      availability_zone: "{{ agent.availability_zone }}"
+      networks:
+        - port: { get_resource: {{ agent.id }}_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          template: |
+            #!/bin/sh
+            screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
+          params:
+            "$SERVER_ENDPOINT": { get_param: server_endpoint }
+            "$AGENT_ID": {{ agent.id }}
+
+{% if agent.mode == 'master' %}
+  {{ agent.id }}_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_resource: north_private_net }
+      fixed_ips:
+        - subnet_id: { get_resource: north_private_subnet }
+      security_groups: [{ get_resource: server_security_group }]
+{% else %}
+  {{ agent.id }}_port:
+    type: OS::Neutron::Port
+    properties:
+      network_id: { get_resource: south_private_net }
+      fixed_ips:
+        - subnet_id: { get_resource: south_private_subnet }
+      security_groups: [{ get_resource: server_security_group }]
+
+  {{ agent.id }}_floating_ip:
+    type: OS::Neutron::FloatingIP
+    depends_on: router_interface_2
+    properties:
+      floating_network: { get_param: external_net }
+      port_id: { get_resource: {{ agent.id }}_port }
+{% endif %}
+
+{% endfor %}
+
+outputs:
+{% for agent in agents.values() %}
+  {{ agent.id }}_instance_name:
+    value: { get_attr: [ {{ agent.id }}, instance_name ] }
+{% if agent.mode == 'master' %}
+  {{ agent.id }}_ip:
+    value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [north_private_net, name] }, 0 ] }
+{% else %}
+  {{ agent.id }}_ip:
+    value: { get_attr: [ {{ agent.id }}_floating_ip, floating_ip_address ] }
+{% endif %}
+{% endfor %}
diff --git a/scenarios/essential/l3/perf_l3_east_west.yaml b/scenarios/essential/l3/perf_l3_east_west.yaml
new file mode 100644
index 0000000..12da58b
--- /dev/null
+++ b/scenarios/essential/l3/perf_l3_east_west.yaml
@@ -0,0 +1,35 @@
+title: OpenStack L3 East-West Performance
+
+description:
+  In this scenario Shaker launches 1 pair of instances, each instance on its own
+  compute node. Instances are connected to one of 2 tenant networks, which
+  plugged into single router. The traffic goes from one network to the other
+  (L3 east-west).
+
+deployment:
+  template: l3_east_west.hot
+  accommodation: [pair, single_room, compute_nodes: 2]
+
+execution:
+  tests:
+  -
+    title: Ping
+    class: flent
+    method: ping
+    time: 10
+    sla:
+    - "[type == 'agent'] >> (stats.ping_icmp.avg < 2.0)"
+  -
+    title: TCP
+    class: iperf3
+    sla:
+    - "[type == 'agent'] >> (stats.bandwidth.avg > 5000)"
+    - "[type == 'agent'] >> (stats.retransmits.max < 10)"
+  -
+    title: UDP
+    class: iperf3
+    udp: on
+    bandwidth: 0
+    datagram_size: 32
+    sla:
+    - "[type == 'agent'] >> (stats.packets.avg > 100000)"
diff --git a/scenarios/essential/l3/perf_l3_north_south.yaml b/scenarios/essential/l3/perf_l3_north_south.yaml
new file mode 100644
index 0000000..34a521a
--- /dev/null
+++ b/scenarios/essential/l3/perf_l3_north_south.yaml
@@ -0,0 +1,35 @@
+title: OpenStack L3 North-South Performance
+
+description:
+  In this scenario Shaker launches 1 pair of instances on different compute
+  nodes. Instances are in different networks connected to different routers,
+  master accesses slave by floating ip. The traffic goes from one network
+  via external network to the other network.
+
+deployment:
+  template: l3_north_south.hot
+  accommodation: [pair, single_room, compute_nodes: 2]
+
+execution:
+  tests:
+  -
+    title: Ping
+    class: flent
+    method: ping
+    time: 10
+    sla:
+    - "[type == 'agent'] >> (stats.ping_icmp.avg < 2.0)"
+  -
+    title: TCP
+    class: iperf3
+    sla:
+    - "[type == 'agent'] >> (stats.bandwidth.avg > 5000)"
+    - "[type == 'agent'] >> (stats.retransmits.max < 10)"
+  -
+    title: UDP
+    class: iperf3
+    udp: on
+    bandwidth: 0
+    datagram_size: 32
+    sla:
+    - "[type == 'agent'] >> (stats.packets.avg > 100000)"
diff --git a/scenarios/essential/l3/udp_l3_east_west.yaml b/scenarios/essential/l3/udp_l3_east_west.yaml
new file mode 100644
index 0000000..d5596a3
--- /dev/null
+++ b/scenarios/essential/l3/udp_l3_east_west.yaml
@@ -0,0 +1,21 @@
+title: OpenStack L3 East-West UDP
+
+description:
+  In this scenario Shaker launches pairs of instances, each instance on its own
+  compute node. Instances are connected to one of 2 tenant networks, which
+  plugged into single router. The traffic goes from one network to the other
+  (L3 east-west). The load is generated by UDP traffic.
+
+deployment:
+  template: l3_east_west.hot
+  accommodation: [pair, single_room]
+
+execution:
+  progression: quadratic
+  tests:
+  -
+    title: UDP
+    class: iperf3
+    udp: on
+    bandwidth: 1000M
+    datagram_size: 32
diff --git a/scenarios/essential/l3/udp_l3_north_south.yaml b/scenarios/essential/l3/udp_l3_north_south.yaml
new file mode 100644
index 0000000..1938645
--- /dev/null
+++ b/scenarios/essential/l3/udp_l3_north_south.yaml
@@ -0,0 +1,22 @@
+title: OpenStack L3 North-South UDP
+
+description:
+  In this scenario Shaker launches pairs of instances on different compute
+  nodes. Instances are in different networks connected to different routers,
+  master accesses slave by floating ip. The traffic goes from one network
+  via external network to the other network. The load is generated by UDP
+  traffic.
+
+deployment:
+  template: l3_north_south.hot
+  accommodation: [pair, single_room]
+
+execution:
+  progression: quadratic
+  tests:
+  -
+    title: UDP
+    class: iperf3
+    udp: on
+    bandwidth: 1000M
+    datagram_size: 32