RIFT OSM R1 Initial Submission
[osm/SO.git] / rwlaunchpad / ra / pytest / ns / pingpong / test_scaling.py
diff --git a/rwlaunchpad/ra/pytest/ns/pingpong/test_scaling.py b/rwlaunchpad/ra/pytest/ns/pingpong/test_scaling.py
new file mode 100644 (file)
index 0000000..0878db7
--- /dev/null
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+"""
+# 
+#   Copyright 2016 RIFT.IO Inc
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#
+
+@file test_scaling.py
+@author Paul Laidler (Paul.Laidler@riftio.com)
+@date 07/13/2016
+@brief Pingpong scaling system test
+"""
+
+import os
+import pytest
+import subprocess
+import sys
+import time
+import uuid
+
+import rift.auto.mano
+import rift.auto.session
+import rift.auto.descriptor
+
+from gi.repository import (
+    NsrYang,
+    NsdYang,
+    VnfrYang,
+    RwNsrYang,
+    RwNsdYang,
+    RwVnfrYang,
+)
+
+@pytest.mark.setup('pingpong_nsd')
+@pytest.mark.depends('launchpad')
+class TestSetupPingpongNsd(object):
+    def test_onboard(self, mgmt_session, descriptors):
+        for descriptor in descriptors:
+            rift.auto.descriptor.onboard(mgmt_session.host, descriptor)
+
+    def test_install_sar(self, mgmt_session):
+        install_cmd = 'ssh {mgmt_ip} -q -n -o BatchMode=yes -o StrictHostKeyChecking=no -- sudo yum install sysstat --assumeyes'.format(
+                mgmt_ip=mgmt_session.host,
+        )
+        subprocess.check_call(install_cmd, shell=True)
+
+
+@pytest.fixture(scope='function', params=[5,10,15,20,25])
+def service_count(request):
+    '''Fixture representing the number of services to test'''
+    return request.param
+
+@pytest.mark.depends('pingpong_nsd')
+class TestScaling(object):
+    @pytest.mark.preserve_fixture_order
+    def test_scaling(self, mgmt_session, cloud_account_name, service_count):
+
+        def start_services(mgmt_session, desired_service_count, max_attempts=3): 
+            catalog = mgmt_session.proxy(NsdYang).get_config('/nsd-catalog')
+            nsd = catalog.nsd[0]
+            
+            nsr_path = "/ns-instance-config"
+            nsr = mgmt_session.proxy(RwNsrYang).get_config(nsr_path)
+            service_count = len(nsr.nsr)
+
+            attempts = 0
+            while attempts < max_attempts and service_count < desired_service_count:
+                attempts += 1
+
+                for count in range(service_count, desired_service_count):
+                    nsr = rift.auto.descriptor.create_nsr(
+                        cloud_account_name,
+                        "pingpong_%s" % str(uuid.uuid4().hex[:10]),
+                        nsd.id)
+                    mgmt_session.proxy(RwNsrYang).create_config('/ns-instance-config/nsr', nsr)
+
+                ns_instance_opdata = mgmt_session.proxy(RwNsrYang).get('/ns-instance-opdata')
+                for nsr in ns_instance_opdata.nsr:
+                    try:
+                        xpath = "/ns-instance-opdata/nsr[ns-instance-config-ref='{}']/operational-status".format(nsr.ns_instance_config_ref)
+                        mgmt_session.proxy(RwNsrYang).wait_for(xpath, "running", fail_on=['failed'], timeout=180)
+                        xpath = "/ns-instance-opdata/nsr[ns-instance-config-ref='{}']/config-status".format(nsr.ns_instance_config_ref)
+                        mgmt_session.proxy(RwNsrYang).wait_for(xpath, "configured", fail_on=['failed'], timeout=450)
+                        service_count += 1
+                    except rift.auto.session.ProxyWaitForError:
+                        mgmt_session.proxy(RwNsrYang).delete_config("/ns-instance-config/nsr[id='{}']".format(nsr.ns_instance_config_ref))
+
+        def monitor_launchpad_performance(service_count, interval=30, samples=1):
+            sar_cmd = "ssh {mgmt_ip} -q -n -o BatchMode=yes -o StrictHostKeyChecking=no -- sar -A {interval} {samples}".format(
+                    mgmt_ip=mgmt_session.host,
+                    interval=interval,
+                    samples=samples
+            )
+            output = subprocess.check_output(sar_cmd, shell=True, stderr=subprocess.STDOUT)
+            outfile = '{rift_artifacts}/scaling_{task_id}.log'.format(
+                    rift_artifacts=os.environ.get('RIFT_ARTIFACTS'),
+                    task_id=os.environ.get('AUTO_TASK_ID')
+            )
+            with open(outfile, 'a') as fh:
+                message = '''
+== SCALING RESULTS : {service_count} Network Services ==
+{output}               
+                '''.format(service_count=service_count, output=output.decode())
+                fh.write(message)
+
+        start_services(mgmt_session, service_count)
+        monitor_launchpad_performance(service_count, interval=30, samples=1)
+
+@pytest.mark.depends('pingpong_nsd')
+@pytest.mark.teardown('pingpong_nsd')
+class TestTeardownPingpongNsr(object):
+    def test_teardown_nsr(self, mgmt_session):
+
+        ns_instance_config = mgmt_session.proxy(RwNsrYang).get_config('/ns-instance-config')
+        for nsr in ns_instance_config.nsr:
+            mgmt_session.proxy(RwNsrYang).delete_config("/ns-instance-config/nsr[id='{}']".format(nsr.id))
+
+        time.sleep(60)
+        vnfr_catalog = mgmt_session.proxy(RwVnfrYang).get('/vnfr-catalog')
+        assert vnfr_catalog is None or len(vnfr_catalog.vnfr) == 0
+
+    def test_generate_plots(self):
+        plot_commands = [
+            ('python {rift_install}/usr/rift/systemtest/util/sarplot.py '
+                    '--plot "{rift_artifacts}/scaling_cpu_{task_id}.png" '
+                    '--title "CPU Utilization by network service count" '
+                    '--keys CPU '
+                    '--fields %usr,%idle,%sys '
+                    '--key-filter CPU:all '
+                    '--ylabel "CPU Utilization %" '
+                    '--xlabel "Network Service Count" '
+                    '--xticklabels "5,10,15,20,25" < {rift_artifacts}/scaling_{task_id}.log'
+            ),
+            ('python {rift_install}/usr/rift/systemtest/util/sarplot.py '
+                    '--plot "{rift_artifacts}/scaling_mem_{task_id}.png" '
+                    '--title "Memory Utilization by network service count" '
+                    '--fields kbmemfree,kbmemused,kbbuffers,kbcached,kbcommit,kbactive,kbinact,kbdirty '
+                    '--ylabel "Memory Utilization" '
+                    '--xlabel "Network Service Count" '
+                    '--xticklabels "5,10,15,20,25" < {rift_artifacts}/scaling_{task_id}.log'
+            ),
+            ('python {rift_install}/usr/rift/systemtest/util/sarplot.py '
+                    '--plot "{rift_artifacts}/scaling_mempct_{task_id}.png" '
+                    '--title "Memory Utilization by network service count" '
+                    '--fields %memused,%commit '
+                    '--ylabel "Memory Utilization %" '
+                    '--xlabel "Network Service Count" '
+                    '--xticklabels "5,10,15,20,25" < {rift_artifacts}/scaling_{task_id}.log'
+            ),
+            ('python {rift_install}/usr/rift/systemtest/util/sarplot.py '
+                    '--plot "{rift_artifacts}/scaling_iface_{task_id}.png" '
+                    '--title "Interface Utilization by network service count" '
+                    '--keys IFACE '
+                    '--fields rxpck/s,txpck/s,rxkB/s,txkB/s,rxcmp/s,txcmp/s,rxmcst/s '
+                    '--key-filter IFACE:eth0 '
+                    '--ylabel "Interface Utilization" '
+                    '--xlabel "Network Service Count" '
+                    '--xticklabels "5,10,15,20,25" < {rift_artifacts}/scaling_{task_id}.log'
+            ),
+            ('python {rift_install}/usr/rift/systemtest/util/sarplot.py '
+                    '--plot "{rift_artifacts}/scaling_iface_err_{task_id}.png" '
+                    '--title "Interface Errors by network service count" '
+                    '--keys IFACE '
+                    '--fields rxerr/s,txerr/s,coll/s,rxdrop/s,txdrop/s,txcarr/s,rxfram/s,rxfifo/s,txfifo/s '
+                    '--key-filter IFACE:eth0 '
+                    '--ylabel "Interface Errors" '
+                    '--xlabel "Network Service Count" '
+                    '--xticklabels "5,10,15,20,25" < {rift_artifacts}/scaling_{task_id}.log'
+            ),
+        ]
+
+        for cmd in plot_commands:
+            subprocess.check_call(
+                    cmd.format(
+                        rift_install=os.environ.get('RIFT_INSTALL'),
+                        rift_artifacts=os.environ.get('RIFT_ARTIFACTS'),
+                        task_id=os.environ.get('AUTO_TASK_ID')
+                    ),
+                    shell=True
+            )
+