This is an automated email from the ASF dual-hosted git repository.

marcoabreu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-mxnet.git


The following commit(s) were added to refs/heads/master by this push:
     new b78265b  [MXNET-793] Virtual testing with Qemu, refinement and extract 
test results to root MXNet folder (#13065)
b78265b is described below

commit b78265bac0dc47c39085184023174be1d40fb172
Author: Pedro Larroy <[email protected]>
AuthorDate: Fri Nov 2 17:53:46 2018 +0100

    [MXNET-793] Virtual testing with Qemu, refinement and extract test results 
to root MXNet folder (#13065)
    
    * Improve Qemu infrastructure
    Add documentation about running it interactively
    
    * Separate provision
    
    * Improve provisioning
    
    * Refine provisioning and interactive
    
    * Cant provision when the volumes arent mounted
    
    * Fix running tests
    
    * raise log output to INFO
    
    * adjust logging
    
    * flush stdout and stderr
    
    * Refine by copying test results back to the host
    
    * Fix license
    
    * remove config file and different way to run QEMU
    
    * remove config file and different way to run QEMU, remove ansible
---
 ci/README.md                             | 20 +++++++++-
 ci/docker/Dockerfile.build.test.arm_qemu |  6 ++-
 ci/docker/install/ubuntu_arm_qemu.sh     |  5 ++-
 ci/docker/qemu/ansible.cfg               | 20 ----------
 ci/docker/qemu/playbook.yml              | 48 ------------------------
 ci/docker/qemu/qemu_run.sh               | 31 ----------------
 ci/docker/qemu/runtime_functions.py      | 35 +++++++++++++-----
 ci/docker/qemu/vmcontrol.py              | 63 +++++++++++++++++++++++++++-----
 8 files changed, 104 insertions(+), 124 deletions(-)

diff --git a/ci/README.md b/ci/README.md
index 3737fc7..6c8a23f 100644
--- a/ci/README.md
+++ b/ci/README.md
@@ -98,5 +98,21 @@ To run the unit tests under qemu:
 ./build.py -p armv7 && ./build.py -p test.arm_qemu ./runtime_functions.py 
run_ut_py3_qemu
 ```
 
-To get a shell on the container and debug issues with the emulator itself:
-Run the output of `./build.py -p test.arm_qemu --print-docker-run`
+To get a shell on the container and debug issues with the emulator itself, we 
build the container
+and then execute it interactively. We can afterwards use port 2222 on the host 
to connect with SSH.
+
+
+```
+ci/build.py -p test.arm_qemu -b && docker run -p2222:2222 -ti 
mxnetci/build.test.arm_qemu
+```
+
+Then from another terminal:
+
+```
+ssh -o StrictHostKeyChecking=no -p 2222 qemu@localhost
+```
+
+There are two pre-configured users: `root` and `qemu` both without passwords.
+
+
+
diff --git a/ci/docker/Dockerfile.build.test.arm_qemu 
b/ci/docker/Dockerfile.build.test.arm_qemu
index fde105c..68891a7 100644
--- a/ci/docker/Dockerfile.build.test.arm_qemu
+++ b/ci/docker/Dockerfile.build.test.arm_qemu
@@ -39,6 +39,8 @@ RUN /work/ubuntu_adduser.sh
 
 COPY runtime_functions.sh /work/
 COPY qemu/* /work/
-COPY qemu/ansible.cfg /etc/ansible/ansible.cfg 
 
-CMD ["./runtime_functions.py","run_ut_py3_qemu"]
+# SSH to the Qemu VM
+EXPOSE 2222/tcp
+
+CMD ["./runtime_functions.py","run_qemu_interactive"]
diff --git a/ci/docker/install/ubuntu_arm_qemu.sh 
b/ci/docker/install/ubuntu_arm_qemu.sh
index c30dc4f..79ab67b 100755
--- a/ci/docker/install/ubuntu_arm_qemu.sh
+++ b/ci/docker/install/ubuntu_arm_qemu.sh
@@ -31,6 +31,7 @@ apt-get install -y \
     qemu-system-arm \
     unzip \
     bzip2 \
-    vim-nox
+    vim-nox \
+    toilet
 
-pip3 install ansible ipython
+pip3 install ipython
diff --git a/ci/docker/qemu/ansible.cfg b/ci/docker/qemu/ansible.cfg
deleted file mode 100644
index 24e2ec8..0000000
--- a/ci/docker/qemu/ansible.cfg
+++ /dev/null
@@ -1,20 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-[defaults]
-host_key_checking = False
-ansible_python_interpreter = /usr/bin/python3
diff --git a/ci/docker/qemu/playbook.yml b/ci/docker/qemu/playbook.yml
deleted file mode 100644
index 3b9e7c5..0000000
--- a/ci/docker/qemu/playbook.yml
+++ /dev/null
@@ -1,48 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
----
-- name: provision QEMU VM
-  hosts: all
-  gather_facts: no
-  become: true
-  become_user: root
-  tasks:
-    - name: Wait until ssh is available
-      wait_for_connection:
-        delay: 0
-        sleep: 3
-        timeout: 400
-    - command: hostname
-      register: h
-    - debug: msg="{{ h.stdout }}"
-
-    - name: copy mxnet artifacts
-      copy:
-        src: "{{ item }}"
-        dest: mxnet_dist/
-      with_fileglob: "/work/mxnet/build/*.whl"
-
-    - name: copy runtime_functions.py
-      copy:
-        src: "/work/runtime_functions.py"
-        dest: .
-    - file:
-        path: runtime_functions.py
-        mode: 0755
-
-
diff --git a/ci/docker/qemu/qemu_run.sh b/ci/docker/qemu/qemu_run.sh
deleted file mode 100755
index 53a6487..0000000
--- a/ci/docker/qemu/qemu_run.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-set -exuo pipefail
-
-qemu-system-arm -M virt -m 1024 \
-  -kernel vmlinuz \
-  -initrd initrd.img \
-  -append 'root=/dev/vda1' \
-  -drive if=none,file=vda.qcow2,format=qcow2,id=hd \
-  -device virtio-blk-device,drive=hd \
-  -netdev user,id=mynet,hostfwd=tcp::2222-:22 \
-  -device virtio-net-device,netdev=mynet \
-  -nographic \
-  -display none
diff --git a/ci/docker/qemu/runtime_functions.py 
b/ci/docker/qemu/runtime_functions.py
index 6cf01b6..5659775 100755
--- a/ci/docker/qemu/runtime_functions.py
+++ b/ci/docker/qemu/runtime_functions.py
@@ -33,6 +33,8 @@ import time
 import sys
 import types
 import glob
+import vmcontrol
+from vmcontrol import qemu_ssh, qemu_provision, qemu_rsync_to_host, VM
 
 def activate_this(base):
     import site
@@ -53,21 +55,24 @@ def activate_this(base):
             sys.path.remove(item)
     sys.path[:0] = new_sys_path
 
+
+
+
 def run_ut_py3_qemu():
+    """Run unit tests in the emulator and copy the results back to the host 
through the mounted
+    volume in /mxnet"""
     from vmcontrol import VM
     with VM() as vm:
-        logging.info("VM provisioning with ansible")
-        check_call(["ansible-playbook", "-v", "-u", "qemu", "-i", 
"localhost:{},".format(vm.ssh_port), "playbook.yml"])
-        logging.info("VM provisioned successfully.")
-        logging.info("sync tests")
-        check_call(['rsync', '-e', 'ssh -p{}'.format(vm.ssh_port), '-a', 
'mxnet/tests', 'qemu@localhost:mxnet'])
+        qemu_provision(vm.ssh_port)
         logging.info("execute tests")
-        check_call(["ssh", "-o", "ServerAliveInterval=5", 
"-p{}".format(vm.ssh_port), "qemu@localhost", "./runtime_functions.py", 
"run_ut_python3_qemu_internal"])
+        qemu_ssh(vm.ssh_port, "./runtime_functions.py", 
"run_ut_python3_qemu_internal")
+        qemu_rsync_to_host(vm.ssh_port, "*.xml", "mxnet")
+        logging.info("copied to host")
         logging.info("tests finished, vm shutdown.")
         vm.shutdown()
 
 def run_ut_python3_qemu_internal():
-    """this runs inside the vm, it's run by the playbook above by ansible"""
+    """this runs inside the vm"""
     pkg = glob.glob('mxnet_dist/*.whl')[0]
     logging.info("=== NOW Running inside QEMU ===")
     logging.info("PIP Installing %s", pkg)
@@ -75,8 +80,20 @@ def run_ut_python3_qemu_internal():
     logging.info("PIP Installing mxnet/tests/requirements.txt")
     check_call(['sudo', 'pip3', 'install', '-r', 
'mxnet/tests/requirements.txt'])
     logging.info("Running tests in mxnet/tests/python/unittest/")
-    check_call(['nosetests', '--with-timer', '--with-xunit', '--xunit-file', 
'nosetests_unittest.xml', '--verbose', 
'mxnet/tests/python/unittest/test_ndarray.py:test_ndarray_fluent'])
+    check_call(['nosetests', '--with-timer', '--with-xunit', '--xunit-file', 
'nosetests_unittest.xml', '--verbose', 'mxnet/tests/python/unittest/'])
+    # Example to run a single unit test:
+    # check_call(['nosetests', '--with-timer', '--with-xunit', '--xunit-file', 
'nosetests_unittest.xml', '--verbose', 
'mxnet/tests/python/unittest/test_ndarray.py:test_ndarray_fluent'])
+
+
+
+def run_qemu_interactive():
+    vm = VM(interactive=True)
+    vm.detach()
+    vm.start()
+    vm.wait()
+    logging.info("QEMU finished")
 
+################################
 
 def parsed_args():
     parser = argparse.ArgumentParser(description="""python runtime 
functions""", epilog="")
@@ -95,7 +112,7 @@ def chdir_to_script_directory():
     os.chdir(base)
 
 def main():
-    logging.getLogger().setLevel(logging.DEBUG)
+    logging.getLogger().setLevel(logging.INFO)
     logging.basicConfig(format='{}: %(asctime)-15s 
%(message)s'.format(script_name()))
     chdir_to_script_directory()
 
diff --git a/ci/docker/qemu/vmcontrol.py b/ci/docker/qemu/vmcontrol.py
index 2262bc7..a7e8c0f 100644
--- a/ci/docker/qemu/vmcontrol.py
+++ b/ci/docker/qemu/vmcontrol.py
@@ -42,6 +42,8 @@ import shlex
 #
 # The VMs are provisioned after boot, tests are run and then they are stopped
 #
+QEMU_SSH_PORT=2222
+QEMU_RAM=4096
 
 QEMU_RUN="""
 qemu-system-arm -M virt -m {ram} \
@@ -55,17 +57,32 @@ qemu-system-arm -M virt -m {ram} \
   -display none -nographic
 """
 
+QEMU_RUN_INTERACTIVE="""
+qemu-system-arm -M virt -m {ram} \
+  -kernel vmlinuz \
+  -initrd initrd.img \
+  -append 'root=/dev/vda1' \
+  -drive if=none,file=vda.qcow2,format=qcow2,id=hd \
+  -device virtio-blk-device,drive=hd \
+  -netdev user,id=mynet,hostfwd=tcp::{ssh_port}-:22 \
+  -device virtio-net-device,netdev=mynet \
+  -nographic
+"""
+
+
 class VMError(RuntimeError):
     pass
 
 class VM:
     """Control of the virtual machine"""
-    def __init__(self, ssh_port=2222):
+    def __init__(self, ssh_port=QEMU_SSH_PORT, ram=QEMU_RAM, 
interactive=False):
         self.log = logging.getLogger(VM.__name__)
         self.ssh_port = ssh_port
         self.timeout_s = 300
         self.qemu_process = None
         self._detach = False
+        self._interactive = interactive
+        self.ram = ram
 
     def __enter__(self):
         self.start()
@@ -77,13 +94,22 @@ class VM:
             self.terminate()
 
     def start(self):
-        self.log.info("Starting VM, ssh port redirected to localhost:%s", 
self.ssh_port)
+        sys.stderr.flush()
+        call(['toilet', '-f', 'smbraille', 'Starting QEMU'])
+        sys.stdout.flush()
+        self.log.info("Starting VM, ssh port redirected to localhost:%s 
(inside docker, not exposed by default)", self.ssh_port)
         if self.is_running():
             raise VMError("VM is running, shutdown first")
-        self.qemu_process = run_qemu(self.ssh_port)
+        if self._interactive:
+            self.qemu_process = 
Popen(shlex.split(QEMU_RUN_INTERACTIVE.format(ssh_port=self.ssh_port, 
ram=self.ram)))
+            return
+        else:
+            self.log.info("Starting in non-interactive mode. Terminal output 
is disabled.")
+            self.qemu_process = 
Popen(shlex.split(QEMU_RUN.format(ssh_port=self.ssh_port, ram=self.ram)), 
stdout=DEVNULL, stdin=DEVNULL, stderr=PIPE)
         def keep_waiting():
             return self.is_running()
 
+        logging.info("waiting for ssh to be open in the VM (timeout 
{}s)".format(self.timeout_s))
         ssh_working = wait_ssh_open('127.0.0.1', self.ssh_port, keep_waiting, 
self.timeout_s)
 
         if not self.is_running():
@@ -140,11 +166,28 @@ class VM:
             logging.info("VM destructor hit")
             self.terminate()
 
-def run_qemu(ssh_port=2222):
-    cmd = QEMU_RUN.format(ssh_port=ssh_port, ram=4096)
-    logging.info("QEMU command: %s", cmd)
-    qemu_process = Popen(shlex.split(cmd), stdout=DEVNULL, stdin=DEVNULL, 
stderr=PIPE)
-    return qemu_process
+
+def qemu_ssh(ssh_port=QEMU_SSH_PORT, *args):
+    check_call(["ssh", "-o", "ServerAliveInterval=5", "-o", 
"StrictHostKeyChecking=no", "-p{}".format(ssh_port), "qemu@localhost", *args])
+
+
+def qemu_rsync(ssh_port, local_path, remote_path):
+    check_call(['rsync', '-e', 'ssh -o StrictHostKeyChecking=no 
-p{}'.format(ssh_port), '-a', local_path, 
'qemu@localhost:{}'.format(remote_path)])
+
+def qemu_rsync_to_host(ssh_port, remote_path, local_path):
+    check_call(['rsync', '-e', 'ssh -o StrictHostKeyChecking=no 
-p{}'.format(ssh_port), '-va', 'qemu@localhost:{}'.format(remote_path), 
local_path])
+
+def qemu_provision(ssh_port=QEMU_SSH_PORT):
+    import glob
+    logging.info("Provisioning the VM with artifacts and sources")
+
+    artifact = glob.glob('/work/mxnet/build/*.whl')
+    for x in artifact:
+        qemu_rsync(ssh_port, x, 'mxnet_dist/')
+    qemu_rsync(ssh_port, '/work/runtime_functions.py','')
+    qemu_rsync(ssh_port, '/work/vmcontrol.py','')
+    qemu_rsync(ssh_port, 'mxnet/tests', 'mxnet')
+    logging.info("Provisioning completed successfully.")
 
 
 def wait_ssh_open(server, port, keep_waiting=None, timeout=None):
@@ -159,7 +202,7 @@ def wait_ssh_open(server, port, keep_waiting=None, 
timeout=None):
     import errno
     import time
     log = logging.getLogger('wait_ssh_open')
-    sleep_s = 0
+    sleep_s = 1
     if timeout:
         from time import time as now
         # time module is needed to calc timeout shared between two exceptions
@@ -183,7 +226,7 @@ def wait_ssh_open(server, port, keep_waiting=None, 
timeout=None):
                     log.debug("connect timeout %d s", next_timeout)
                     s.settimeout(next_timeout)
 
-            log.info("connect %s:%d", server, port)
+            log.debug("connect %s:%d", server, port)
             s.connect((server, port))
             ret = s.recv(1024).decode()
             if ret and ret.startswith('SSH'):

Reply via email to