diff --git a/tests/pre.yml b/tests/pre.yml
index 3f7802226a..075d9ad3e0 100644
--- a/tests/pre.yml
+++ b/tests/pre.yml
@@ -25,11 +25,39 @@
   tasks:
     # NOTE(yoctozepto): we use gawk to add time to each logged line
     # outside of Ansible (e.g. for init-runonce)
-    - name: Install gawk
+    - name: Install gawk and Python modules
       package:
-        name: gawk
+        name:
+          - gawk
+          - python3-pip
+          - python3-setuptools
+          - python3-virtualenv
+          - python3-wheel
       become: true
 
+    # FIXME(hrw): drop when previous_release == ussuri
+    - name: Install Python2 modules for stable/train
+      package:
+        name:
+          - python-pip
+          - python-setuptools
+          - python-virtualenv
+          - python-wheel
+      become: true
+      when:
+        - is_upgrade
+        - previous_release == 'train'
+        - not (ansible_os_family == "RedHat" and ansible_distribution_major_version | int == 8)
+
+    # NOTE(hrw): On RedHat systems it is part of python3-virtualenv
+    - name: Install virtualenv on Debian systems
+      package:
+        name:
+          - virtualenv
+      become: true
+      when:
+        ansible_os_family == "Debian"
+
     - name: Ensure /tmp/logs/ dir
       file:
         path: "{{ logs_dir }}"
diff --git a/zuul.d/base.yaml b/zuul.d/base.yaml
index 42e1fee494..f27ed9d636 100644
--- a/zuul.d/base.yaml
+++ b/zuul.d/base.yaml
@@ -38,6 +38,9 @@
       neutron_external_network_prefix_length: "24"
       neutron_external_interface_name: vxlan1
       tls_enabled: false
+      # NOTE(yoctozepto): Ansible on Debian defaults to /usr/bin/python which is
+      # python2. Let's use python3 instead as expected in 2020 and beyond.
+      ansible_python_interpreter: python3
     roles:
       - zuul: zuul/zuul-jobs