]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
code coverage from source
authorshylesh kumar <shylesh.mohan@gmail.com>
Wed, 22 Aug 2018 01:02:32 +0000 (21:02 -0400)
committershylesh kumar <shylesh.mohan@gmail.com>
Fri, 14 Sep 2018 05:48:16 +0000 (01:48 -0400)
Signed-off-by: shylesh kumar <shylesh.mohan@gmail.com>
qa/suites/rados/downstream/coverage.test/cover-suit.yaml [new file with mode: 0644]
qa/suites/rados/downstream/coverage/% [new file with mode: 0644]
qa/suites/rados/downstream/coverage/ceph.yaml [new file with mode: 0644]
qa/suites/rados/downstream/coverage/tasks/radosbench.yaml [new file with mode: 0644]
qa/suites/rados/downstream/coverage/tasks/radosgw-admin.yaml [new file with mode: 0644]
qa/suites/rados/downstream/coverage/tasks/rbd_fio_perf_4k.yaml [new file with mode: 0644]
qa/suites/rados/downstream/coverage/tasks/readwrite.yaml [new file with mode: 0644]
qa/tasks/collect_coverage.py [new file with mode: 0644]
qa/tasks/make_coverage.py [new file with mode: 0644]
qa/tasks/util/update-cmakelists [new file with mode: 0755]
qa/tasks/util/update-docmake [new file with mode: 0755]

diff --git a/qa/suites/rados/downstream/coverage.test/cover-suit.yaml b/qa/suites/rados/downstream/coverage.test/cover-suit.yaml
new file mode 100644 (file)
index 0000000..1f3b04b
--- /dev/null
@@ -0,0 +1,14 @@
+roles:
+- [mon.0, osd.6, osd.7, osd.8, client.0]
+- [mgr.0,osd.0, osd.1, osd.2, osd.3, osd.4, osd.5]
+
+tasks:
+- make_coverage:
+- ceph:
+    coverage: true
+    conf:
+      osd:
+        osd max object name len : 400
+        osd max object namespace len : 64
+- collect_coverage:
+
diff --git a/qa/suites/rados/downstream/coverage/% b/qa/suites/rados/downstream/coverage/%
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/qa/suites/rados/downstream/coverage/ceph.yaml b/qa/suites/rados/downstream/coverage/ceph.yaml
new file mode 100644 (file)
index 0000000..e7cc441
--- /dev/null
@@ -0,0 +1,11 @@
+tasks:
+- make_coverage:
+- ceph:
+    conf:
+      osd:
+        osd max object name len : 400
+        osd max object namespace len : 64
+- full_sequential_finally:
+  - collect_coverage:
+
+
diff --git a/qa/suites/rados/downstream/coverage/tasks/radosbench.yaml b/qa/suites/rados/downstream/coverage/tasks/radosbench.yaml
new file mode 100644 (file)
index 0000000..9f889fe
--- /dev/null
@@ -0,0 +1,17 @@
+roles:
+- [mon.0, osd.6, osd.7, osd.8, client.0]
+- [mgr.0,osd.0, osd.1, osd.2, osd.3, osd.4, osd.5]
+
+overrides:
+  ceph:
+    conf:
+      mon:
+        osd default pool size: 3
+
+tasks:
+- radosbench:
+    clients: [client.0]
+    time: 720
+    type: rand
+    objectsize: 1048576
+
diff --git a/qa/suites/rados/downstream/coverage/tasks/radosgw-admin.yaml b/qa/suites/rados/downstream/coverage/tasks/radosgw-admin.yaml
new file mode 100644 (file)
index 0000000..6fb6589
--- /dev/null
@@ -0,0 +1,18 @@
+roles:
+- [mon.a, osd.0]
+- [mgr.x, client.0, osd.1, osd.2, osd.3]
+
+overrides:
+  ceph:
+    conf:
+      client:
+        debug ms: 1
+        rgw gc obj min wait: 15
+      osd:
+        debug ms: 1
+        debug objclass : 20
+
+tasks:
+- rgw:
+    client.0:
+- radosgw-admin:
diff --git a/qa/suites/rados/downstream/coverage/tasks/rbd_fio_perf_4k.yaml b/qa/suites/rados/downstream/coverage/tasks/rbd_fio_perf_4k.yaml
new file mode 100644 (file)
index 0000000..7aa3d93
--- /dev/null
@@ -0,0 +1,19 @@
+roles:
+- [mon.0, osd.6, osd.7, osd.8, client.0]
+- [mgr.0,osd.0, osd.1, osd.2, osd.3, osd.4, osd.5]
+
+overrides:
+  ceph:
+    conf:
+      mon:
+        osd default pool size: 3
+
+tasks:
+- rbd_fio:
+    client.0:
+      fio-io-size: 80%
+      formats: [2]
+      features: [[layering],[layering,exclusive-lock,object-map]]
+      io-engine: rbd
+      rw: randrw
+      runtime: 600
diff --git a/qa/suites/rados/downstream/coverage/tasks/readwrite.yaml b/qa/suites/rados/downstream/coverage/tasks/readwrite.yaml
new file mode 100644 (file)
index 0000000..05dfa33
--- /dev/null
@@ -0,0 +1,19 @@
+roles:
+- [mon.0, osd.6, osd.7, osd.8, client.0]
+- [mgr.0,osd.0, osd.1, osd.2, osd.3, osd.4, osd.5]
+
+overrides:
+  ceph:
+    crush_tunables: optimal
+    conf:
+      mon:
+        mon osd initial require min compat client: luminous
+tasks:
+- rados:
+    clients: [client.0]
+    ops: 4000
+    objects: 500
+    op_weights:
+      read: 45
+      write: 45
+      delete: 10
diff --git a/qa/tasks/collect_coverage.py b/qa/tasks/collect_coverage.py
new file mode 100644 (file)
index 0000000..fea0dd3
--- /dev/null
@@ -0,0 +1,151 @@
+'''
+Compiling ceph from source on each node
+for code coverage runs
+'''
+import contextlib
+import logging
+import os
+import re
+import shlex
+import subprocess
+
+from subprocess import Popen
+from cStringIO import StringIO
+from teuthology import misc as teuthology
+from teuthology.parallel import parallel
+from teuthology.orchestra import run, remote
+from teuthology.config import config as teuth_config
+
+log = logging.getLogger(__name__)
+COVERAGE_LOGS="/a/code_coverage_logs/"
+run_dir=""
+
+def aggregate_info(ctx, tdir, curator, ilist, run_dir):
+       '''
+       Aggregate the results from all the nodes to generate
+       a single .info file
+       '''
+
+       coverdir="/tmp/coverage"
+       JID_PREFIX=os.path.basename(ctx.archive)
+       cmd = "mkdir -p {}".format(coverdir)
+       r=curator.run(args=cmd)
+       dst=""
+
+       mergefile=coverdir+"/coverage_merged.info"
+
+       cmd="lcov --rc  lcov_branch_coverage=1 "
+       for ent in ilist:
+               addstr=" -a "+tdir+ent
+               tstr=" -t "+ent.split(".")[0]
+               cmd = cmd + addstr+tstr
+       cmd = cmd +" -o "+mergefile
+       log.info(cmd)
+
+       r=curator.run(args=cmd)
+
+       '''
+         rename file with JID_PREFIX
+       '''
+       new_mergefile=coverdir+"/"+JID_PREFIX+"_coverage_merged.info"
+       cmd = "mv "+mergefile+" "+new_mergefile
+       log.info("renaming {src} to {dst}".format(src=mergefile,\
+                       dst=new_mergefile))
+       log.info(cmd)
+       r=curator.run(args=cmd)
+
+       '''
+         transfer file to teuthology master node
+       '''
+       assert(os.path.exists(run_dir))
+       dst=curator.get_file(new_mergefile, False, run_dir)
+       assert(os.path.exists(dst))
+       log.info("xfrd file {} to {}".format(new_mergefile, dst))
+
+
+       '''
+       cmd="genhtml -o {archive_dir} {coverfile}".format( \
+               archive_dir=coverdir, coverfile=mergefile)
+       log.info(cmd)
+       r=curator.run(args=cmd)
+       teuthology.pull_directory(curator, coverdir, ctx.archive)
+       '''
+
+def _gather_data(ctx, remote, rpath, curator):
+       tdir="/tmp/cov/"+ctx.archive
+       lpath=""
+       if remote != curator:
+               if not os.path.exists(tdir):
+                       os.makedirs(tdir)
+               lpath=remote.get_file(rpath, False, tdir)
+               assert(os.path.exists(lpath))
+               log.info("Transfered file {} to {} ".format(rpath, lpath))
+               #pass the file to curator
+               # direct copying from remote->remote not working
+               fn=os.path.basename(rpath)
+               src=tdir+"/{fn}".format(fn=fn)
+
+               with file(src, 'rb') as f:
+                       teuthology.sudo_write_file(
+                               remote=curator,
+                               path=rpath,
+                               data=f,
+                       )
+                       remote.run(
+                               args=[
+                                       'sudo',
+                                       'chmod',
+                                       'a=rx',
+                                       '--',
+                                       rpath,
+                               ]
+                       )
+
+
+
+def gather_data(ctx, config, remote, srcdir, curator):
+       this_infofile="{hostname}.info".format(hostname=remote.shortname)
+       ''' Generate .info file on respective nodes and copy it to
+            local node
+       '''
+       cmd="sudo bash -c '(cd /sourcebuild/ceph && \
+               exec lcov --rc lcov_branch_coverage=1 \
+               --capture -d . --output-file {nodename})'"\
+                       .format(nodename=this_infofile)
+       log.info(cmd)
+       r=remote.run(args=cmd)
+
+       _gather_data(ctx, remote, srcdir+this_infofile, curator)
+
+@contextlib.contextmanager
+def task(ctx, config):
+       """
+       generate reports on respective nodes but fetch all of them to local
+       so that we can merge the reports
+       """
+       global run_dir
+       srcdir="/sourcebuild/ceph/"
+       dstdir="{ctxdir}/".format(ctxdir=ctx.archive)
+       run_dir=COVERAGE_LOGS+os.path.basename(os.path.dirname(ctx.archive))+"/"
+
+
+       if os.path.exists(dstdir):
+               print 'coverage directory present'
+       else:
+               os.makedirs(dstdir)
+       curator=ctx.cluster.remotes.keys()[0]
+
+       with parallel() as ptask:
+               for remote, roles in ctx.cluster.remotes.iteritems():
+                       ptask.spawn(gather_data, ctx, config, remote, srcdir, curator)
+       ilist=[]
+       for remote, roles in ctx.cluster.remotes.iteritems():
+               node=remote.shortname+".info"
+               ilist.append(node)
+
+       aggregate_info(ctx, srcdir, curator, ilist, run_dir)
+       yield
+
+       log.info("DONE WITH COLLECTION")
+
+
diff --git a/qa/tasks/make_coverage.py b/qa/tasks/make_coverage.py
new file mode 100644 (file)
index 0000000..1efaff9
--- /dev/null
@@ -0,0 +1,240 @@
+'''
+Compiling ceph from source on each node
+for code coverage runs
+'''
+import contextlib
+import logging
+import os
+import re
+import shlex
+import subprocess
+
+from cStringIO import StringIO
+from teuthology import misc as teuthology
+from teuthology.parallel import parallel
+from teuthology.orchestra import run
+from teuthology.config import config as teuth_config
+
+log = logging.getLogger(__name__)
+COVERAGE_LOGS = "/a/code_coverage_logs/"
+
+
+def get_sourcedir(ctx, config, remote, rdir):
+       '''
+       get source code directory along with gcno files
+        on the machine where we want to generate report
+       '''
+       ldir = "/tmp/build/{}/".format(os.path.basename(os.path.dirname(ctx.archive)))
+       if not os.path.exists(ldir):
+               os.makedirs(ldir)
+#o     teuthology.pull_directory(remote, rdir, ldir)
+       cmd="scp -r {rhost}:{rpath} {lpath}".format(\
+               rhost=remote.name, rpath=rdir, \
+               lpath=ldir)
+       log.info(cmd)
+
+       p=subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE)
+       p_stdout=p.communicate()[0]
+       log.info(p_stdout)
+
+
+def copy_compile_utils(ctx, config, remote):
+       FILES=['update-cmakelists', 'update-docmake']
+       destdir = '/usr/bin'
+       for filename in FILES:
+               log.info('Shipping %r...', filename)
+               src = os.path.join(os.path.dirname(__file__), "util/"+filename)
+               dst = os.path.join(destdir, filename)
+               with file(src, 'rb') as f:
+                       teuthology.sudo_write_file(
+                               remote=remote,
+                               path=dst,
+                               data=f,
+                       )
+                       remote.run(
+                               args=[
+                                   'sudo',
+                                   'chmod',
+                                   'a=rx',
+                                    '--',
+                                    dst,
+                                ]
+                       )
+
+
+def copy_utils(ctx, config, remote):
+       FILES = ['daemon-helper', 'adjust-ulimits']
+       destdir = '/usr/bin'
+       for filename in FILES:
+               log.info('Shipping %r...', filename)
+               src = os.path.join(os.path.dirname(teuthology.__file__), "task/install/"+filename)
+               dst = os.path.join(destdir, filename)
+               with file(src, 'rb') as f:
+                   teuthology.sudo_write_file(
+                       remote=remote,
+                       path=dst,
+                       data=f,
+                   )
+                   f.seek(0)
+                   remote.run(
+                       args=[
+                           'sudo',
+                           'chmod',
+                           'a=rx',
+                           '--',
+                           dst,
+                       ]
+                   )
+
+
+def get_dependencies(ctx, config, remote):
+       #1. enable repos
+       #2. get dependencies
+       cmd='sudo subscription-manager --force register \
+               --serverurl=subscription.rhsm.stage.redhat.com:443/subscription \
+               --baseurl=https://cdn.stage.redhat.com --username=qa@redhat.com \
+               --password=redhatqa --auto-attach'
+       r=remote.run(args=cmd)
+       cmd='sudo subscription-manager repos --enable=rhel-7-server-extras-rpms'
+       r=remote.run(args=cmd)
+       cmd='sudo subscription-manager repos --enable=rhel-7-server-optional-rpms'
+       r=remote.run(args=cmd)
+       cmd='sudo sed -i -- \'s/enabled=0/enabled=1/g\' /etc/yum.repos.d/epel.repo'
+       r=remote.run(args=cmd)
+       cmd='sudo yum repolist'
+       r=remote.run(args=cmd)
+
+       cmd = "sudo bash -c '(cd /sourcebuild/ceph && exec git checkout luminous)'"
+       r=remote.run(args=cmd)
+       cmd="sudo bash -c '(cd /sourcebuild/ceph && exec  git submodule update --init --recursive)'"
+       r=remote.run(args=cmd)
+       cmd='sudo sed -i -- \'s/yum install subscription-manager/yum install \
+               -y subscription-manager/g\' /sourcebuild/ceph/install-deps.sh'
+       r=remote.run(args=cmd)
+       cmd="sudo bash -c '(cd /sourcebuild/ceph && exec  ./install-deps.sh)'"
+       r=remote.run(args=cmd)
+       cmd="sudo bash -c '(sudo  yum -y install lcov)'"
+       r=remote.run(args=cmd)
+
+       copy_compile_utils(ctx, config, remote)
+
+       #edit CMakefiles.txt and do_cmake.sh according to gcov need
+       cmd="sudo update-cmakelists " + "/sourcebuild/ceph/CMakeLists.txt"
+       r=remote.run(args=cmd)
+       #1. set INSTALL_PREFIX=/usr in do_cmake
+       cmd="sudo update-docmake " + "/sourcebuild/ceph/do_cmake.sh"
+       r=remote.run(args=cmd)
+
+       #cmd="sudo bash -c '(cd /sourcebuild/ceph && source scl_source enable devtoolset-7 && exec ./do_cmake.sh)'"
+       cmd="sudo bash -c '(cd /sourcebuild/ceph && exec ./do_cmake.sh)'"
+       r=remote.run(args=cmd)
+       cmd="sudo bash -c '(cd /sourcebuild/ceph/build && exec make -j4)'"
+       r=remote.run(args=cmd)
+       cmd="sudo bash -c '(cd /sourcebuild/ceph/build && exec make install)'"
+       r=remote.run(args=cmd)
+       #cmd="sudo bash -c '(cp -ar  /usr/local/lib64/python2.7/site-packages/* /usr/lib64/python2.7/site-packages/)'"
+       #r=remote.run(args=cmd)
+       cmd="sudo mkdir /etc/ceph"
+       r=remote.run(args=cmd)
+       cmd="sudo mkdir /var/log/ceph"
+       r=remote.run(args=cmd)
+       cmd="sudo mkdir /var/lib/ceph"
+       r=remote.run(args=cmd)
+
+       ''' copy adjust-ulimits, daemon-helper scripts '''
+       copy_utils(ctx, config, remote)
+
+       #update permissions for testdir so that
+       # teuthology can delete archive/coverage/gcda files
+       test_dir=teuthology.get_testdir(ctx)
+       cmd="sudo chmod -R 0777 {tdir}".format(tdir=test_dir)
+       r=remote.run(args=cmd)
+
+       #before CEPH task
+       #- ceph:
+           #conf:
+            # osd:
+            #   osd max object name len : 400
+            #   osd max object namespace len : 64
+       #TODO
+       #gather gcda files
+       #aggreagate
+       #publish report
+
+
+def start_compile(ctx, config, remote, builddir):
+       #1. edit cmakefile for gcov entry
+       #2.compile
+       pass
+
+
+def compile_with_gcov(ctx, config, grepo, remote, builddir):
+       ''' please use variables once task working'''
+       try:
+               r = remote.run(args=['sudo', 'mkdir', '/sourcebuild'], \
+                               )
+       except:
+               pass
+
+       r = remote.run (args=['sudo', 'git','config',\
+                               '--global','http.sslVerify', 'false']
+                               )
+#      r = remote.run(args=['sudo', 'git', 'clone',\
+#                      'https://gitlab.cee.redhat.com/ceph/ceph.git','/sourcebuild/ceph'], timeout=3600,\
+#                      check_status=False, wait=True)
+
+       r = remote.run(args=['sudo', 'git', 'clone',\
+                       'https://github.com/ceph/ceph.git','/sourcebuild/ceph'], timeout=3600,\
+                       check_status=False, wait=True)
+
+       get_dependencies(ctx, config, remote)
+       #start_compile()
+
+
+
+
+@contextlib.contextmanager
+def task(ctx, config):
+       """
+       This will replace Install task for the tests.
+       fetch source from a git repo on all the nodes and compile
+       them locally. this is because we need to preserve .gcno files
+       for gcov report generation purpose.
+
+       ex:
+       - tasks:
+           make-coverage:
+           ceph:
+           radosbench:
+       """
+       ''' Hard coding for POC purpose'''
+
+       grepo="https://gitlab.cee.redhat.com/ceph/ceph.git"
+       builddir="/sourcebuild/ceph/"
+
+       with parallel() as ptask:
+               for remote, roles in ctx.cluster.remotes.iteritems():
+                       ptask.spawn(compile_with_gcov, ctx, config, grepo, remote, builddir)
+
+
+       '''
+       Transfer source dir which has gcno files and source
+       only from one node
+       '''
+
+       log.info("Transferring the source directory")
+       remote=next(iter(ctx.cluster.remotes))
+       get_sourcedir(ctx, config, remote, builddir)
+
+       '''create dir with run name in COVERAGE_LOGS directory'''
+       rundir=COVERAGE_LOGS+os.path.basename(os.path.dirname(ctx.archive))
+       log.info("rundir = {}".format(rundir))
+       try:
+               os.mkdir(rundir)
+       except:
+               log.error("Failed to create rundir")
+
+       yield
+       #TODO: cleanup still pending
+
+
diff --git a/qa/tasks/util/update-cmakelists b/qa/tasks/util/update-cmakelists
new file mode 100755 (executable)
index 0000000..57751ef
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/bash
+dst=$1
+
+sudo sed -i '/option.WITH_TSAN/ i\option(WITH_GCOV "build with gcov" ON)\
+if(WITH_GCOV)\
+  find_program(HAVE_GCOV gcov)\
+  if(NOT HAVE_GCOV)\
+    message(FATAL_ERROR "Coverage Enabled but gcov Not Found")\
+  endif(NOT HAVE_GCOV)\
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -O0")\
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")\
+  list(APPEND EXTRALIBS gcov)\
+endif(WITH_GCOV)\n
+' $1
diff --git a/qa/tasks/util/update-docmake b/qa/tasks/util/update-docmake
new file mode 100755 (executable)
index 0000000..07c4ad5
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/bash
+dest=$1
+sed -i '/^cmake/ s/cmake/cmake\ -DCMAKE_INSTALL_PREFIX=\/usr/' $1