Merge "Update DEVSTACK_SERIES to train"
diff --git a/.zuul.yaml b/.zuul.yaml
index 7ee7598..62e8753 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -232,6 +232,7 @@
         '{{ devstack_log_dir }}/dstat-csv.log': logs
         '{{ devstack_log_dir }}/devstacklog.txt': logs
         '{{ devstack_log_dir }}/devstacklog.txt.summary': logs
+        '{{ devstack_log_dir }}/tcpdump.pcap': logs
         '{{ devstack_full_log}}': logs
         '{{ stage_dir }}/verify_tempest_conf.log': logs
         '{{ stage_dir }}/apache': logs
diff --git a/doc/source/debugging.rst b/doc/source/debugging.rst
new file mode 100644
index 0000000..fd0d9cd
--- /dev/null
+++ b/doc/source/debugging.rst
@@ -0,0 +1,46 @@
+=====================
+System-wide debugging
+=====================
+
+A lot can go wrong during a devstack run, and there are a few inbuilt
+tools to help you.
+
+dstat
+-----
+
+Enable the ``dstat`` service to produce performance logs during the
+devstack run.  These will be logged to the journal and also as a CSV
+file.
+
+memory_tracker
+--------------
+
+The ``memory_tracker`` service periodically monitors RAM usage and
+provides consumption output when available memory is seen to be
+falling (i.e. processes are consuming memory).  It also provides
+output showing locked (unswappable) memory.
+
+tcpdump
+-------
+
+Enable the ``tcpdump`` service to run a background tcpdump.  You must
+set the ``TCPDUMP_ARGS`` variable to something suitable (there is no
+default).  For example, to trace iSCSI communication during a job in
+the OpenStack gate and copy the result into the log output, you might
+use:
+
+.. code-block:: yaml
+
+   job:
+     name: devstack-job
+     parent: devstack
+     vars:
+       devstack_services:
+         tcpdump: true
+       devstack_localrc:
+         TCPDUMP_ARGS: "-i any tcp port 3260"
+       zuul_copy_output:
+         '{{ devstack_log_dir }}/tcpdump.pcap': logs
+
+
+
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 9186f6d..1ea1c5d 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -38,22 +38,23 @@
 Install Linux
 -------------
 
-Start with a clean and minimal install of a Linux system. Devstack
+Start with a clean and minimal install of a Linux system. DevStack
 attempts to support the two latest LTS releases of Ubuntu, the
 latest/current Fedora version, CentOS/RHEL 7, as well as Debian and
 OpenSUSE.
 
-If you do not have a preference, Ubuntu 16.04 is the most tested, and
-will probably go the smoothest.
+If you do not have a preference, Ubuntu 18.04 (Bionic Beaver) is the
+most tested, and will probably go the smoothest.
 
-Add Stack User
---------------
+Add Stack User (optional)
+-------------------------
 
-Devstack should be run as a non-root user with sudo enabled
+DevStack should be run as a non-root user with sudo enabled
 (standard logins to cloud images such as "ubuntu" or "cloud-user"
 are usually fine).
 
-You can quickly create a separate `stack` user to run DevStack with
+If you are not using a cloud image, you can create a separate `stack` user
+to run DevStack with
 
 .. code-block:: console
 
@@ -76,12 +77,12 @@
    $ cd devstack
 
 The ``devstack`` repo contains a script that installs OpenStack and
-templates for configuration files
+templates for configuration files.
 
 Create a local.conf
 -------------------
 
-Create a ``local.conf`` file with 4 passwords preset at the root of the
+Create a ``local.conf`` file with four passwords preset at the root of the
 devstack git repo.
 
 .. code-block:: ini
diff --git a/files/rpms-suse/n-novnc b/files/rpms-suse/n-novnc
deleted file mode 100644
index c8722b9..0000000
--- a/files/rpms-suse/n-novnc
+++ /dev/null
@@ -1 +0,0 @@
-python-numpy
diff --git a/files/rpms-suse/n-spice b/files/rpms-suse/n-spice
deleted file mode 100644
index c8722b9..0000000
--- a/files/rpms-suse/n-spice
+++ /dev/null
@@ -1 +0,0 @@
-python-numpy
diff --git a/files/rpms/n-novnc b/files/rpms/n-novnc
deleted file mode 100644
index 24ce15a..0000000
--- a/files/rpms/n-novnc
+++ /dev/null
@@ -1 +0,0 @@
-numpy
diff --git a/files/rpms/n-spice b/files/rpms/n-spice
deleted file mode 100644
index 24ce15a..0000000
--- a/files/rpms/n-spice
+++ /dev/null
@@ -1 +0,0 @@
-numpy
diff --git a/files/rpms/nova b/files/rpms/nova
index 4140cd7..8d73644 100644
--- a/files/rpms/nova
+++ b/files/rpms/nova
@@ -13,7 +13,6 @@
 m2crypto
 mysql-devel
 mysql-server # NOPRIME
-numpy # needed by websockify for spice console
 parted
 polkit
 rabbitmq-server # NOPRIME
diff --git a/inc/python b/inc/python
index 0926330..19e1228 100644
--- a/inc/python
+++ b/inc/python
@@ -49,16 +49,9 @@
     fi
     $xtrace
 
-    if python3_enabled && [[ "$os_VENDOR" == "CentOS" ]] || \
-    [[ "$os_VENDOR" == "Fedora" && $os_RELEASE -gt 26 ]]; then
-        # Default Python 3 install prefix changed to /usr/local in Fedora 27:
-        # https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe
-        echo "/usr/local/bin"
-    elif is_fedora || is_suse; then
-        echo "/usr/bin"
-    else
-        echo "/usr/local/bin"
-    fi
+    local PYTHON_PATH=/usr/local/bin
+    ( is_fedora && ! python3_enabled ) || is_suse && PYTHON_PATH=/usr/bin
+    echo $PYTHON_PATH
 }
 
 # Wrapper for ``pip install`` that only installs versions of libraries
@@ -88,34 +81,6 @@
     pip_install $clean_name[$extras]
 }
 
-# Determine the python versions supported by a package
-function get_python_versions_for_package {
-    local name=$1
-    cd $name && python setup.py --classifiers \
-        | grep 'Language' | cut -f5 -d: | grep '\.' | tr '\n' ' '
-}
-
-# Check for python3 classifier in local directory
-function check_python3_support_for_package_local {
-    local name=$1
-    cd $name
-    set +e
-    classifier=$(python setup.py --classifiers \
-        | grep 'Programming Language :: Python :: 3')
-    set -e
-    echo $classifier
-}
-
-# Check for python3 classifier on pypi
-function check_python3_support_for_package_remote {
-    local name=$1
-    set +e
-    classifier=$(curl -s -L "https://pypi.python.org/pypi/$name/json" \
-        | grep '"Programming Language :: Python :: 3"')
-    set -e
-    echo $classifier
-}
-
 # python3_enabled_for() assumes the service(s) specified as arguments are
 # enabled for python 3 unless explicitly disabled. See python3_disabled_for().
 #
@@ -266,52 +231,20 @@
             cmd_pip=$(get_pip_command $PYTHON2_VERSION)
             local sudo_pip="sudo -H"
             if python3_enabled; then
-                # Look at the package classifiers to find the python
-                # versions supported, and if we find the version of
-                # python3 we've been told to use, use that instead of the
-                # default pip
-                local python_versions
-
                 # Special case some services that have experimental
                 # support for python3 in progress, but don't claim support
                 # in their classifier
                 echo "Check python version for : $package_dir"
                 if python3_disabled_for ${package_dir##*/}; then
                     echo "Explicitly using $PYTHON2_VERSION version to install $package_dir based on DISABLED_PYTHON3_PACKAGES"
-                elif python3_enabled_for ${package_dir##*/}; then
+                else
+                    # For everything that is not explicitly blacklisted with
+                    # DISABLED_PYTHON3_PACKAGES, assume it supports python3
+                    # and we will let pip sort out the install, regardless of
+                    # the package being local or remote.
                     echo "Using $PYTHON3_VERSION version to install $package_dir based on default behavior"
                     sudo_pip="$sudo_pip LC_ALL=en_US.UTF-8"
                     cmd_pip=$(get_pip_command $PYTHON3_VERSION)
-                elif [[ -d "$package_dir" ]]; then
-                    python_versions=$(get_python_versions_for_package $package_dir)
-                    if [[ $python_versions =~ $PYTHON3_VERSION ]]; then
-                        echo "Automatically using $PYTHON3_VERSION version to install $package_dir based on classifiers"
-                        sudo_pip="$sudo_pip LC_ALL=en_US.UTF-8"
-                        cmd_pip=$(get_pip_command $PYTHON3_VERSION)
-                    else
-                        # The package may not have yet advertised python3.5
-                        # support so check for just python3 classifier and log
-                        # a warning.
-                        python3_classifier=$(check_python3_support_for_package_local $package_dir)
-                        if [[ ! -z "$python3_classifier" ]]; then
-                            echo "Automatically using $PYTHON3_VERSION version to install $package_dir based on local package settings"
-                            sudo_pip="$sudo_pip LC_ALL=en_US.UTF-8"
-                            cmd_pip=$(get_pip_command $PYTHON3_VERSION)
-                        else
-                            echo "WARNING: Did not find python 3 classifier for local package $package_dir"
-                        fi
-                    fi
-                else
-                    # Check pypi as we don't have the package on disk
-                    package=$(echo $package_dir | grep -o '^[.a-zA-Z0-9_-]*')
-                    python3_classifier=$(check_python3_support_for_package_remote $package)
-                    if [[ ! -z "$python3_classifier" ]]; then
-                        echo "Automatically using $PYTHON3_VERSION version to install $package based on remote package settings"
-                        sudo_pip="$sudo_pip LC_ALL=en_US.UTF-8"
-                        cmd_pip=$(get_pip_command $PYTHON3_VERSION)
-                    else
-                        echo "WARNING: Did not find python 3 classifier for remote package $package_dir"
-                    fi
                 fi
             fi
         fi
diff --git a/lib/nova b/lib/nova
index 7c6f8cd..dee798c 100644
--- a/lib/nova
+++ b/lib/nova
@@ -183,6 +183,10 @@
 # and Glance.
 NOVA_USE_SERVICE_TOKEN=$(trueorfalse False NOVA_USE_SERVICE_TOKEN)
 
+# Enable debugging levels for iscsid service (goes from 0-8)
+ISCSID_DEBUG=$(trueorfalse False ISCSID_DEBUG)
+ISCSID_DEBUG_LEVEL=${ISCSID_DEBUG_LEVEL:-4}
+
 # Functions
 # ---------
 
@@ -327,8 +331,22 @@
                 sudo chown -R $STACK_USER $NOVA_INSTANCES_PATH
             fi
         fi
+
+        if [[ ${ISCSID_DEBUG} == "True" ]]; then
+            # Install an override that starts iscsid with debugging
+            # enabled.
+            cat > /tmp/iscsid.override <<EOF
+[Service]
+ExecStart=
+ExecStart=/usr/sbin/iscsid -d${ISCSID_DEBUG_LEVEL}
+EOF
+            sudo mkdir -p /etc/systemd/system/iscsid.service.d
+            sudo mv /tmp/iscsid.override /etc/systemd/system/iscsid.service.d/override.conf
+            sudo systemctl daemon-reload
+        fi
+
         # ensure that iscsid is started, even when disabled by default
-        start_service iscsid
+        restart_service iscsid
     fi
 
     # Rebuild the config file from scratch
diff --git a/lib/tcpdump b/lib/tcpdump
new file mode 100644
index 0000000..16e8269
--- /dev/null
+++ b/lib/tcpdump
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# lib/tcpdump
+# Functions to start and stop a tcpdump
+
+# Dependencies:
+#
+# - ``functions`` file
+
+# ``stack.sh`` calls the entry points in this order:
+#
+# - start_tcpdump
+# - stop_tcpdump
+
+# Save trace setting
+_XTRACE_TCPDUMP=$(set +o | grep xtrace)
+set +o xtrace
+
+TCPDUMP_OUTPUT=${TCPDUMP_OUTPUT:-$LOGDIR/tcpdump.pcap}
+
+# e.g. for iscsi
+#  "-i any tcp port 3260"
+TCPDUMP_ARGS=${TCPDUMP_ARGS:-""}
+
+# start_tcpdump() - Start running processes
+function start_tcpdump {
+    # Run a tcpdump with given arguments and save the packet capture
+    if is_service_enabled tcpdump; then
+        if [[ -z "${TCPDUMP_ARGS}" ]]; then
+            die $LINENO "The tcpdump service requires TCPDUMP_ARGS to be set"
+        fi
+        touch ${TCPDUMP_OUTPUT}
+        run_process tcpdump "/usr/sbin/tcpdump -w $TCPDUMP_OUTPUT $TCPDUMP_ARGS" root root
+    fi
+}
+
+# stop_tcpdump() stop tcpdump process
+function stop_tcpdump {
+    stop_process tcpdump
+}
+
+# Restore xtrace
+$_XTRACE_TCPDUMP
diff --git a/lib/tempest b/lib/tempest
index e9463a1..a8f107a 100644
--- a/lib/tempest
+++ b/lib/tempest
@@ -255,6 +255,9 @@
     # and the public_network_id should not be set.
     if [[ "$NEUTRON_CREATE_INITIAL_NETWORKS" == "True" ]] && is_networking_extension_supported 'external-net'; then
         public_network_id=$(openstack network show -f value -c id $PUBLIC_NETWORK_NAME)
+        # make sure shared network presence does not confuses the tempest tests
+        openstack network create --share shared
+        openstack subnet create --description shared-subnet --subnet-range ${TEMPEST_SHARED_POOL:-192.168.233.0/24} --network shared shared-subnet
     fi
 
     iniset $TEMPEST_CONFIG DEFAULT use_syslog $SYSLOG
diff --git a/roles/export-devstack-journal/README.rst b/roles/export-devstack-journal/README.rst
index a34e070..9e3c919 100644
--- a/roles/export-devstack-journal/README.rst
+++ b/roles/export-devstack-journal/README.rst
@@ -1,11 +1,15 @@
 Export journal files from devstack services
 
-Export the systemd journal for every devstack service in native
-journal format as well as text.  Also, export a syslog-style file with
-kernal and sudo messages.
+This performs a number of logging collection services
 
-Writes the output to the ``logs/`` subdirectory of
-``stage_dir``.
+* Export the systemd journal in native format
+* For every devstack service, export logs to text in a file named
+  ``screen-*`` to maintain legacy compatability when devstack services
+  used to run in a screen session and were logged separately.
+* Export a syslog-style file with kernel and sudo messages for legacy
+  compatability.
+
+Writes the output to the ``logs/`` subdirectory of ``stage_dir``.
 
 **Role Variables**
 
diff --git a/roles/export-devstack-journal/tasks/main.yaml b/roles/export-devstack-journal/tasks/main.yaml
index 6e760c1..cbec444 100644
--- a/roles/export-devstack-journal/tasks/main.yaml
+++ b/roles/export-devstack-journal/tasks/main.yaml
@@ -6,32 +6,49 @@
     state: directory
     owner: "{{ ansible_user }}"
 
-# TODO: convert this to ansible
-- name: Export journal files
+- name: Export legacy stack screen log files
   become: true
   shell:
     cmd: |
       u=""
       name=""
-      for u in `systemctl list-unit-files | grep devstack | awk '{print $1}'`; do
+      for u in $(systemctl list-unit-files | grep devstack | awk '{print $1}'); do
         name=$(echo $u | sed 's/devstack@/screen-/' | sed 's/\.service//')
         journalctl -o short-precise --unit $u | gzip - > {{ stage_dir }}/logs/$name.txt.gz
       done
 
-      # Export the journal in export format to make it downloadable
-      # for later searching. It can then be rewritten to a journal native
-      # format locally using systemd-journal-remote. This makes a class of
-      # debugging much easier. We don't do the native conversion here as
-      # some distros do not package that tooling.
-      journalctl -u 'devstack@*' -o export | \
-          xz --threads=0 - > {{ stage_dir }}/logs/devstack.journal.xz
-
-      # The journal contains everything running under systemd, we'll
-      # build an old school version of the syslog with just the
-      # kernel and sudo messages.
+- name: Export legacy syslog.txt
+  become: true
+  shell:
+    # The journal contains everything running under systemd, we'll
+    # build an old school version of the syslog with just the
+    # kernel and sudo messages.
+    cmd: |
       journalctl \
           -t kernel \
           -t sudo \
           --no-pager \
           --since="$(cat {{ devstack_base_dir }}/log-start-timestamp.txt)" \
         | gzip - > {{ stage_dir }}/logs/syslog.txt.gz
+
+# TODO: convert this to ansible
+#  - make a list of the above units
+#  - iterate the list here
+- name: Export journal
+  become: true
+  shell:
+    # Export the journal in export format to make it downloadable
+    # for later searching. It can then be rewritten to a journal native
+    # format locally using systemd-journal-remote. This makes a class of
+    # debugging much easier. We don't do the native conversion here as
+    # some distros do not package that tooling.
+    cmd: |
+      journalctl -o export \
+          --since="$(cat {{ devstack_base_dir }}/log-start-timestamp.txt)" \
+        | xz --threads=0 - > {{ stage_dir }}/logs/devstack.journal.xz
+
+- name: Save journal README
+  become: true
+  template:
+    src: devstack.journal.README.txt.j2
+    dest: '{{ stage_dir }}/logs/devstack.journal.README.txt'
diff --git a/roles/export-devstack-journal/templates/devstack.journal.README.txt.j2 b/roles/export-devstack-journal/templates/devstack.journal.README.txt.j2
new file mode 100644
index 0000000..598eb7f
--- /dev/null
+++ b/roles/export-devstack-journal/templates/devstack.journal.README.txt.j2
@@ -0,0 +1,33 @@
+Devstack systemd journal
+========================
+
+The devstack.journal file is a copy of the systemd journal during the
+devstack run.
+
+To use it, you will need to convert it so journalctl can read it
+locally.  After downloading the file:
+
+ $ /lib/systemd/systemd-journal-remote <(xzcat ./devstack.journal.xz) -o output.journal
+
+Note this binary is not in the regular path.  On Debian/Ubuntu
+platforms, you will need to have the "sytemd-journal-remote" package
+installed.
+
+It should result in something like:
+
+ Finishing after writing <large number> entries
+
+You can then use journalctl to examine this file.  For example, to see
+all devstack services try:
+
+ $ journalctl --file ./output.journal -u 'devstack@*'
+
+To see just cinder API server logs restrict the match with
+
+ $ journalctl --file ./output.journal -u 'devstack@c-api'
+
+There may be many types of logs available in the journal, a command like
+
+ $ journalctl --file ./output.journal --output=json-pretty | grep "_SYSTEMD_UNIT" | sort -u
+
+can help you find interesting things to filter on.
\ No newline at end of file
diff --git a/roles/write-devstack-local-conf/library/devstack_local_conf.py b/roles/write-devstack-local-conf/library/devstack_local_conf.py
index 8df8dea..2f97d0e 100644
--- a/roles/write-devstack-local-conf/library/devstack_local_conf.py
+++ b/roles/write-devstack-local-conf/library/devstack_local_conf.py
@@ -252,7 +252,11 @@
         if localrc:
             vg = VarGraph(localrc)
             for k, v in vg.getVars():
-                self.localrc.append('{}={}'.format(k, v))
+                # Avoid double quoting
+                if len(v) and v[0]=='"':
+                    self.localrc.append('{}={}'.format(k, v))
+                else:
+                    self.localrc.append('{}="{}"'.format(k, v))
                 if k == 'LIBS_FROM_GIT':
                     lfg = True
                 elif k == 'TEMPEST_PLUGINS':
diff --git a/roles/write-devstack-local-conf/library/test.py b/roles/write-devstack-local-conf/library/test.py
index 2900949..7c526b3 100644
--- a/roles/write-devstack-local-conf/library/test.py
+++ b/roles/write-devstack-local-conf/library/test.py
@@ -185,7 +185,25 @@
             for line in f:
                 if line.startswith('LIBS_FROM_GIT'):
                     lfg = line.strip().split('=')[1]
-        self.assertEqual('oslo.db', lfg)
+        self.assertEqual('"oslo.db"', lfg)
+
+    def test_avoid_double_quote(self):
+        "Test that there a no duplicated quotes"
+        localrc = {'TESTVAR': '"quoted value"'}
+        p = dict(localrc=localrc,
+                 base_services=[],
+                 base_dir='./test',
+                 path=os.path.join(self.tmpdir, 'test.local.conf'),
+                 projects={})
+        lc = self._init_localconf(p)
+        lc.write(p['path'])
+
+        testvar = None
+        with open(p['path']) as f:
+            for line in f:
+                if line.startswith('TESTVAR'):
+                    testvar = line.strip().split('=')[1]
+        self.assertEqual('"quoted value"', testvar)
 
     def test_plugin_circular_deps(self):
         "Test that plugins with circular dependencies fail"
@@ -265,7 +283,7 @@
         lc.write(p['path'])
 
         tp = self._find_tempest_plugins_value(p['path'])
-        self.assertEqual('someplugin', tp)
+        self.assertEqual('"someplugin"', tp)
         self.assertEqual(len(lc.warnings), 1)
 
 
diff --git a/stack.sh b/stack.sh
index 022d5b9..0d7e623 100755
--- a/stack.sh
+++ b/stack.sh
@@ -614,6 +614,7 @@
 source $TOP_DIR/lib/neutron
 source $TOP_DIR/lib/ldap
 source $TOP_DIR/lib/dstat
+source $TOP_DIR/lib/tcpdump
 source $TOP_DIR/lib/etcd3
 
 # Extras Source
@@ -832,6 +833,18 @@
     install_etcd3
 fi
 
+# Setup TLS certs
+# ---------------
+
+# Do this early, before any webservers are set up to ensure
+# we don't run into problems with missing certs when apache
+# is restarted.
+if is_service_enabled tls-proxy; then
+    configure_CA
+    init_CA
+    init_cert
+fi
+
 # Check Out and Install Source
 # ----------------------------
 
@@ -856,13 +869,6 @@
     install_neutronclient
 fi
 
-# Setup TLS certs
-if is_service_enabled tls-proxy; then
-    configure_CA
-    init_CA
-    init_cert
-fi
-
 # Install middleware
 install_keystonemiddleware
 
@@ -1053,6 +1059,12 @@
 # A better kind of sysstat, with the top process per time slice
 start_dstat
 
+# Run a background tcpdump for debugging
+# Note: must set TCPDUMP_ARGS with the enabled service
+if is_service_enabled tcpdump; then
+    start_tcpdump
+fi
+
 # Etcd
 # -----
 
diff --git a/tools/dstat.sh b/tools/dstat.sh
index 01c6d9b..e6cbb0f 100755
--- a/tools/dstat.sh
+++ b/tools/dstat.sh
@@ -12,8 +12,17 @@
 # Retrieve log directory as argument from calling script.
 LOGDIR=$1
 
+DSTAT_TOP_OPTS="--top-cpu-adv --top-io-adv --top-mem"
+if dstat --version | grep -q 'pcp-dstat' ; then
+    # dstat is unmaintained, and moving to a plugin of performance
+    # co-pilot.  Fedora 29 for example has rolled this out.  It's
+    # mostly compatible, except for a few options which are not
+    # implemented (yet?)
+    DSTAT_TOP_OPTS=""
+fi
+
 # Command line arguments for primary DStat process.
-DSTAT_OPTS="-tcmndrylpg --top-cpu-adv --top-io-adv --top-mem --swap --tcp"
+DSTAT_OPTS="-tcmndrylpg ${DSTAT_TOP_OPTS} --swap --tcp"
 
 # Command-line arguments for secondary background DStat process.
 DSTAT_CSV_OPTS="-tcmndrylpg --tcp --output $LOGDIR/dstat-csv.log"
diff --git a/tools/fixup_stuff.sh b/tools/fixup_stuff.sh
index a939e30..1ff7bfa 100755
--- a/tools/fixup_stuff.sh
+++ b/tools/fixup_stuff.sh
@@ -202,7 +202,19 @@
             # install requests with the bundled urllib3 to avoid conflicts
             pip_install --upgrade --force-reinstall requests
         fi
+
     fi
+
+    # Since pip10, pip will refuse to uninstall files from packages
+    # that were created with distutils (rather than more modern
+    # setuptools).  This is because it technically doesn't have a
+    # manifest of what to remove.  However, in most cases, simply
+    # overwriting works.  So this hacks around those packages that
+    # have been dragged in by some other system dependency
+    sudo rm -rf /usr/lib/python2.7/site-packages/enum34*.egg-info
+    sudo rm -rf /usr/lib/python2.7/site-packages/ipaddress*.egg-info
+    sudo rm -rf /usr/lib/python2.7/site-packages/ply-*.egg-info
+    sudo rm -rf /usr/lib/python2.7/site-packages/typing-*.egg-info
 }
 
 function fixup_suse {