[WIP] ONOS-8091 Port python script and utilities to python3

Steps performed so far:
- Updated bash scripts and similar to explicitly invoke python3 (instead of python)
- Updated all python scripts using 2to3

Testing these changes will be a major headache because:
- different scripts are executed in different environments
  (e.g., Jenkins, cell servers, tutorial VMs, etc.)
- we don’t have control on all environments
- some environments we used to control have been dismissed
  (e.g., cell servers)

The approach for now is to focus on the essentials:
- Jenkins jobs for pre-merge and release

Test and fix everything else as the need arises.

Change-Id: I943e214760c9dea9a7ded0d47ef08adbc0ed0bec
diff --git a/.bazelrc b/.bazelrc
index 3e1a905..0de6875 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -16,7 +16,7 @@
 build --java_toolchain=@org_onosproject_onos//tools/build/jdk:default_toolchain
 build --host_java_toolchain=@org_onosproject_onos//tools/build/jdk:default_toolchain
 
-build --host_force_python=PY2
+build --host_force_python=PY3
 
 build --nouse_ijars
 build --experimental_strict_action_env
diff --git a/Dockerfile b/Dockerfile
index f4fb784..45d1aeb 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -10,7 +10,6 @@
 ENV BUILD_DEPS \
     ca-certificates \
     zip \
-    python \
     python3 \
     git \
     bzip2 \
diff --git a/README.md b/README.md
index 3d91143..853c1bf 100644
--- a/README.md
+++ b/README.md
@@ -37,8 +37,7 @@
 * zip
 * curl
 * unzip
-* python2.7
-* python3 (needed by Bazel)
+* python3
 
 ### Build ONOS from source
 
diff --git a/apps/simplefabric/mininet-simplefabric.py b/apps/simplefabric/mininet-simplefabric.py
index dafbbc6..238f268 100755
--- a/apps/simplefabric/mininet-simplefabric.py
+++ b/apps/simplefabric/mininet-simplefabric.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 # Mininet model for Simple Leaf-Spine Network
 
 # Copyright 2017-present Open Networking Foundation
diff --git a/tools/build/bazel/dependencies_pom_generator.py b/tools/build/bazel/dependencies_pom_generator.py
index f2df0c2..2eefc1a 100755
--- a/tools/build/bazel/dependencies_pom_generator.py
+++ b/tools/build/bazel/dependencies_pom_generator.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright 2019-present Open Networking Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,7 @@
 def resolve(mvn_coord):
     mvn_pieces = mvn_coord.split(":")
     if mvn_pieces[0] != "mvn":
-        raise ("Invalid Maven coordinate: %s" % mvn_coord)
+        raise "Invalid Maven coordinate: %s"
     return dict(
         groupId=mvn_pieces[1],
         artifactId=mvn_pieces[2],
@@ -79,7 +79,7 @@
                 dep_template.format(scope='test', **deps[x])
                 for x in test_deps])
         else:
-            for old, new in var_dict.items():
+            for old, new in list(var_dict.items()):
                 line = line.replace(old, new)
             new_lines.append(line)
 
@@ -111,7 +111,7 @@
     for var in args.vars:
         pieces = var.split('=')
         if len(pieces) != 2:
-            raise ("Invalid var '%s'" % var)
+            raise "Invalid var '%s'"
         processed_vars["<!-- %s -->" % pieces[0]] = pieces[1]
 
     generate_pom(
diff --git a/tools/build/bazel/onos_app_bundler.py b/tools/build/bazel/onos_app_bundler.py
index 6c4ca68..5aa77a0 100755
--- a/tools/build/bazel/onos_app_bundler.py
+++ b/tools/build/bazel/onos_app_bundler.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 """
  Copyright 2018-present Open Networking Foundation
 
@@ -60,5 +60,5 @@
         print('There must be an even number of args: file mvn_coords')
         sys.exit(2)
 
-    files = zip(*[iter(args)]*2)
+    files = list(zip(*[iter(args)]*2))
     generateOar(output, files)
diff --git a/tools/build/bazel/onos_app_tools.py b/tools/build/bazel/onos_app_tools.py
index 9979ab5..d780634 100755
--- a/tools/build/bazel/onos_app_tools.py
+++ b/tools/build/bazel/onos_app_tools.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 """
  Copyright 2018-present Open Networking Foundation
 
diff --git a/tools/build/bazel/osgi_feature_bundler.py b/tools/build/bazel/osgi_feature_bundler.py
index a4550e0..f390c88 100755
--- a/tools/build/bazel/osgi_feature_bundler.py
+++ b/tools/build/bazel/osgi_feature_bundler.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 """
  Copyright 2018-present Open Networking Foundation
 
@@ -56,5 +56,5 @@
         print('There must be an even number of args: file mvn_coords')
         sys.exit(2)
 
-    files = zip(*[iter(args)]*2)
+    files = list(zip(*[iter(args)]*2))
     writeFeatureBundle(output, files)
diff --git a/tools/build/bazel/pom_generator.py b/tools/build/bazel/pom_generator.py
index 2e16f49..1ad54ec 100755
--- a/tools/build/bazel/pom_generator.py
+++ b/tools/build/bazel/pom_generator.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 """
  Copyright 2018-present Open Networking Foundation
 
@@ -49,7 +49,7 @@
         with open(name, "w") as file:
             file.write(msg)
     else:
-        print msg
+        print(msg)
 
 
 def write_pom(output, coords, deps):
@@ -70,7 +70,7 @@
     import sys
 
     if len(sys.argv) < 3:
-        print 'usage: pom_generator pom.xml maven_coords dep_coords1 dep_coords2 ...'
+        print('usage: pom_generator pom.xml maven_coords dep_coords1 dep_coords2 ...')
         sys.exit(1)
 
     output = sys.argv[1]
diff --git a/tools/build/check-uploaded-maven-artifacts b/tools/build/check-uploaded-maven-artifacts
index 05819f1..2dfc4ad 100755
--- a/tools/build/check-uploaded-maven-artifacts
+++ b/tools/build/check-uploaded-maven-artifacts
@@ -1,5 +1,4 @@
-#! /usr/bin/env python
-
+#! /usr/bin/env python3
 # Spot checks some published artifacts to be sure that they uploaded correctly
 # to the release repository
 
@@ -12,7 +11,7 @@
 from requests.auth import HTTPBasicAuth
 
 if len(sys.argv) != 4:
-    print "usage: check-uploaded-maven-artifact version buildRoot repoRoot"
+    print("usage: check-uploaded-maven-artifact version buildRoot repoRoot")
     sys.exit(1)
 
 version = sys.argv[1]
@@ -24,8 +23,8 @@
     repoResponse = requests.head(remoteUrl)
 
     if repoResponse.status_code != 200:
-        print 'Cannot find jar file artifact at ' + remoteUrl
-        print repoResponse.text
+        print('Cannot find jar file artifact at ' + remoteUrl)
+        print(repoResponse.text)
         sys.exit(1)
 
     remoteSize = int(repoResponse.headers['content-length'])
@@ -38,7 +37,7 @@
     expectedSha1 = localArtifactSha.hexdigest()
 
     if localSize != remoteSize:
-        print 'Size for ' + remoteUrl + ' is wrong local ' + str(localSize) + ' but found remote ' + str(remoteSize)
+        print('Size for ' + remoteUrl + ' is wrong local ' + str(localSize) + ' but found remote ' + str(remoteSize))
         sys.exit(1)
 
     sha1 = ''
@@ -49,8 +48,8 @@
         sha1 = repoResponse.headers['x-checksum-sha1']
 
     if sha1 != expectedSha1:
-        print 'SHA1 hash is wrong for ' + remoteUrl + ' expected ' + \
-              expectedSha1 + ' but found ' + sha1
+        print('SHA1 hash is wrong for ' + remoteUrl + ' expected ' + \
+              expectedSha1 + ' but found ' + sha1)
         sys.exit(1)
 
 def checkArtifactsForComponent(version, name, component, buildRoot, repoRoot):
diff --git a/tools/build/onos-close-staging b/tools/build/onos-close-staging
index e70d119..1e37ef3 100755
--- a/tools/build/onos-close-staging
+++ b/tools/build/onos-close-staging
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 #
 # This script finds an open staging repository, checks that it contains an
 # expected artifact, attemps to close the repository, and checks that it is closed.
@@ -29,7 +29,7 @@
       resp.raise_for_status()
       return resp
     except requests.exceptions.HTTPError as e:
-      print 'Encountered error:', e
+      print('Encountered error:', e)
       error = e
       time.sleep(1)
   if error:
@@ -46,7 +46,7 @@
       resp.raise_for_status()
       return resp
     except requests.exceptions.HTTPError as e:
-      print 'Encountered error:', e
+      print('Encountered error:', e)
       error = e
       time.sleep(1)
   if error:
@@ -64,11 +64,11 @@
       repos.append(( entry['repositoryId'], entry['profileId'] ))
   
   if len(repos) > 1:
-    print 'Aborting... too many open staging repos'
-    print repos
+    print('Aborting... too many open staging repos')
+    print(repos)
     sys.exit(1)
   elif len(repos) == 0:
-    print 'Aborting... there are no open staging repos'
+    print('Aborting... there are no open staging repos')
     sys.exit(1)
 
   return repos[0]  
@@ -131,8 +131,8 @@
     if event['name'] == 'repositoryClosed':
       return True
     elif event['name'] == 'repositoryCloseFailed':
-      print 'Aborting... repository failed to close'
-      print json.dumps(activity, sort_keys=True, indent=2, separators=(',', ': '))
+      print('Aborting... repository failed to close')
+      print(json.dumps(activity, sort_keys=True, indent=2, separators=(',', ': ')))
       sys.exit(1)
   return False
 
@@ -144,12 +144,12 @@
     sys.stdout.write('.')
     sys.stdout.flush()     
     time.sleep(2)
-  print ' Closed.'
+  print(' Closed.')
 
 if __name__ == '__main__':
   repositoryId, profileId = getStagingRepo(GROUP_ID)
-  print 'Repository Id:', repositoryId
-  print 'Profile Id:', profileId
+  print('Repository Id:', repositoryId)
+  print('Profile Id:', profileId)
 
   checkStagingRepo(repositoryId, ARTIFACT, GROUP_ID, VERSION)
 
@@ -158,5 +158,5 @@
   waitClosed(repositoryId)
 
   if '-d' in sys.argv:
-    print 'Dropping repo %s' % repositoryId
+    print('Dropping repo %s' % repositoryId)
     dropRepo(repositoryId, profileId)
diff --git a/tools/build/onos-prepare-sonar b/tools/build/onos-prepare-sonar
index 1520d9c..feac3fb 100755
--- a/tools/build/onos-prepare-sonar
+++ b/tools/build/onos-prepare-sonar
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 """
 This script prepares this ONOS directory so that the Sonar Scanner can be run.
@@ -161,7 +161,7 @@
         for coverage_target in coverage_targets_result:
             run_coverage_command.append(str(coverage_target))
     except CalledProcessError:
-        print "Error querying test files for target " + target
+        print("Error querying test files for target " + target)
         return
 
     try:
@@ -175,7 +175,7 @@
         # Find the source files used by the tests
         test_sources = run_command(['bazel', 'query', tests_query])
     except CalledProcessError as exc:
-        print "Error running test files for target " + target
+        print("Error running test files for target " + target)
         raise exc
 
     if not os.path.exists('/tmp/jacoco.exec'):
@@ -317,7 +317,7 @@
     with open(SONAR_PROPERTIES_FILE_NAME, 'w') as out:
         out.write(ROOT_TEMPLATE % sonar_parameters)
         for target in targets:
-            print "Processing coverage for target " + target
+            print("Processing coverage for target " + target)
             write_module(target, out)
 
 
diff --git a/tools/build/onos-release-prerequisites b/tools/build/onos-release-prerequisites
index 92e201d..c1605ac 100755
--- a/tools/build/onos-release-prerequisites
+++ b/tools/build/onos-release-prerequisites
@@ -50,7 +50,7 @@
 
 # Tests availability of the required tools
 function testToolchain {
-    for tool in bash python git java javac mvn tar; do
+    for tool in bash python3 git java javac mvn tar; do
         testTool $tool;
     done
     testGerritTool
diff --git a/tools/build/onos-upload-artifacts.py b/tools/build/onos-upload-artifacts.py
index a9b24c5..d5f0079 100755
--- a/tools/build/onos-upload-artifacts.py
+++ b/tools/build/onos-upload-artifacts.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 """
  Copyright 2018-present Open Networking Foundation
 
@@ -147,8 +147,8 @@
         with open(file, 'rb') as f:
             r = requests.post(url, data=f.read(), headers=headers, auth=(SONATYPE_USER, SONATYPE_PASSWORD))
             if r.status_code != 201:
-                print (r.status_code)
-                print (r.text)
+                print((r.status_code))
+                print((r.text))
                 sys.exit(1)
     else:
         # deploy to local repo
@@ -165,7 +165,7 @@
 
 
 def upload_file(src, dest):
-    print ("publishing: " + dest.replace("org/onosproject", ""))
+    print(("publishing: " + dest.replace("org/onosproject", "")))
     files = generate_metadata_files(src, dest)
     stage_files(files, dest)
 
@@ -174,7 +174,7 @@
     import sys
 
     if len(sys.argv) < 2:
-        print 'USAGE: upload-maven-artifacts catalog-file-name [nexus root url]'
+        print('USAGE: upload-maven-artifacts catalog-file-name [nexus root url]')
         sys.exit(1)
 
     input_list_file = sys.argv[1]
@@ -191,20 +191,20 @@
 
     if destination_repo_url is not None:
         if SONATYPE_USER is None:
-            print "Environment variable SONATYPE_USER must be set"
+            print("Environment variable SONATYPE_USER must be set")
             sys.exit(1)
 
         if SONATYPE_PASSWORD is None:
-            print "Environment variable SONATYPE_PASSWORD must be set"
+            print("Environment variable SONATYPE_PASSWORD must be set")
             sys.exit(1)
 
         if SONATYPE_PROFILE is None:
-            print "Environment variable SONATYPE_PROFILE must be set"
+            print("Environment variable SONATYPE_PROFILE must be set")
             sys.exit(1)
 
-        print ("Uploading to remote repo: " + destination_repo_url)
+        print(("Uploading to remote repo: " + destination_repo_url))
     else:
-        print ("Installing in local repo: " + local_maven_repo)
+        print(("Installing in local repo: " + local_maven_repo))
 
     list_file = open(input_list_file, "r")
     lines = list_file.readlines()
diff --git a/tools/build/onosUploadBits.py b/tools/build/onosUploadBits.py
index ae88b5c..03327c9 100755
--- a/tools/build/onosUploadBits.py
+++ b/tools/build/onosUploadBits.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -----------------------------------------------------------------------------
 # Uploads ONOS distributable bits.
 # -----------------------------------------------------------------------------
@@ -29,7 +29,7 @@
         if match:
             version = match.group(1)
             if target_version is not None and version != target_version:
-                print 'Skipping %s...' % filePath
+                print('Skipping %s...' % filePath)
                 continue
             build = match.group(2)
             if build:
diff --git a/tools/build/uploadToS3.py b/tools/build/uploadToS3.py
index 720878c..40ebe34 100755
--- a/tools/build/uploadToS3.py
+++ b/tools/build/uploadToS3.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 """
 Upload a file to S3
 """
@@ -20,7 +20,7 @@
         key = basename( filename )
     else:
         key = dest + basename( filename ) #FIXME add the /
-    print '* Uploading', filename, 'to bucket', bucket, 'as', key
+    print('* Uploading', filename, 'to bucket', bucket, 'as', key)
     stdout.flush()
     start = time()
     def callback( transmitted, size ):
@@ -28,9 +28,9 @@
         elapsed = time() - start
         percent = 100.0 * transmitted / size
         kbps = .001 * transmitted / elapsed
-        print ( '\r%d bytes transmitted of %d (%.2f%%),'
+        print(( '\r%d bytes transmitted of %d (%.2f%%),'
                 ' %.2f KB/sec ' %
-                ( transmitted, size, percent, kbps ) ),
+                ( transmitted, size, percent, kbps ) ), end=' ')
         stdout.flush()
     conn = S3Connection()
     bucket = conn.get_bucket( bucket )
@@ -38,11 +38,11 @@
     k.key = key
     if overwrite or not k.exists():
         k.set_contents_from_filename( filename, cb=callback, num_cb=100 )
-        print
+        print()
         elapsed = time() - start
-        print "* elapsed time: %.2f seconds" % elapsed
+        print("* elapsed time: %.2f seconds" % elapsed)
     else:
-        print 'file', basename( filename ), 'already exists in', bucket.name
+        print('file', basename( filename ), 'already exists in', bucket.name)
 
 def testAccess( bucket=None ):
     "Verify access to a bucket"
@@ -51,7 +51,7 @@
 
     conn = S3Connection()
     bucket = conn.get_bucket( bucket )
-    print bucket.get_acl()
+    print(bucket.get_acl())
 
 
 if __name__ == '__main__':
diff --git a/tools/dev/Dockerfile-dev b/tools/dev/Dockerfile-dev
index d589ba0..87316c3 100644
--- a/tools/dev/Dockerfile-dev
+++ b/tools/dev/Dockerfile-dev
@@ -20,7 +20,7 @@
 WORKDIR /src/onos
 RUN apt-get update && \
         DEBIAN_FRONTEND=noninteractive \
-        apt-get install -y zip python git bzip2 build-essential && \
+        apt-get install -y zip python3 git bzip2 build-essential && \
         export ONOS_ROOT=/src/onos && \
         mkdir -p /src/tar && \
         cd /src/tar && \
diff --git a/tools/dev/bash_profile b/tools/dev/bash_profile
index eaff4b3..f6a9543 100644
--- a/tools/dev/bash_profile
+++ b/tools/dev/bash_profile
@@ -77,7 +77,7 @@
 alias ole='olo "ERROR|WARN|Exception|Error"'
 
 # Pretty-print JSON output
-alias pp='python -m json.tool'
+alias pp='python3 -m json.tool'
 
 # Short-hand to launch Java API docs, REST API docs and ONOS GUI
 alias docs='open $ONOS_ROOT/docs/target/site/apidocs/index.html'
diff --git a/tools/dev/bin/branch-clean b/tools/dev/bin/branch-clean
index 17960b0..87f303b 100755
--- a/tools/dev/bin/branch-clean
+++ b/tools/dev/bin/branch-clean
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 from subprocess import check_output
 import sys
@@ -31,21 +31,21 @@
     one_by_one = '--one-by-one' in sys.argv
     to_delete = get_merged_branches_by_change_id()
     if len(to_delete) == 0:
-        print "Nothing to clean"
+        print("Nothing to clean")
         sys.exit(0)
     for branch in to_delete:
         if dry_run:
-            print branch
+            print(branch)
         else:
             if one_by_one:
-                print 'Do you want to delete branch %s [y/N]' % branch
-                ans = raw_input()
+                print('Do you want to delete branch %s [y/N]' % branch)
+                ans = input()
                 if ans == 'y' or ans == 'Y':
-                    print delete_branch(branch)
+                    print(delete_branch(branch))
             else:
-                    print delete_branch(branch)
+                    print(delete_branch(branch))
     
     if dry_run:
-        print '*****************************************************************'
-        print 'Did not actually delete anything yet, pass in --confirm to delete'
-        print 
+        print('*****************************************************************')
+        print('Did not actually delete anything yet, pass in --confirm to delete')
+        print() 
diff --git a/tools/dev/bin/branch-compare b/tools/dev/bin/branch-compare
index 2ea535d..24a82f1 100755
--- a/tools/dev/bin/branch-compare
+++ b/tools/dev/bin/branch-compare
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 import os
 import re
@@ -42,7 +42,7 @@
   try:
     sourceRef, targetRef = sys.argv[1:3]
   except ValueError:
-    print 'branch-compare <source ref> <target ref>'
+    print('branch-compare <source ref> <target ref>')
 
   targetCommits = getCommits(sourceRef, targetRef)
   sourceCommits = getCommits(targetRef, sourceRef)
@@ -51,5 +51,5 @@
   
   for id in missingCommitsFromTarget:
     hash = sourceCommits[id]
-    print 'git cherry-pick', hash
-    print commitMsgs[hash] 
+    print('git cherry-pick', hash)
+    print(commitMsgs[hash]) 
diff --git a/tools/dev/bin/onos-gen-bazel-project b/tools/dev/bin/onos-gen-bazel-project
index 355193a..bb3c4a1 100755
--- a/tools/dev/bin/onos-gen-bazel-project
+++ b/tools/dev/bin/onos-gen-bazel-project
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python3
 import os
 
 import subprocess
@@ -43,12 +43,12 @@
         "script_name": os.path.basename(__file__),
         "language_level": JAVA_LANGUAGE_LEVEL,
         "exclude_dirs": "\n".join(
-            map(lambda x: "  -" + x, EXCLUDE_DIRECTORIES)),
-        "targets": "\n".join(map(lambda x: "  " + x, all_targets)),
-        "test_sources": "\n".join(map(lambda x: "  " + x, TEST_SOURCES)),
+            ["  -" + x for x in EXCLUDE_DIRECTORIES]),
+        "targets": "\n".join(["  " + x for x in all_targets]),
+        "test_sources": "\n".join(["  " + x for x in TEST_SOURCES]),
     }
     return TEMPLATE.format(**data)
 
 
 if __name__ == "__main__":
-    print gen_project()
+    print(gen_project())
diff --git a/tools/dev/bin/onos-gen-p4-constants b/tools/dev/bin/onos-gen-p4-constants
index 07530d6..5a5aa06 100755
--- a/tools/dev/bin/onos-gen-p4-constants
+++ b/tools/dev/bin/onos-gen-p4-constants
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python3
 # -*- utf-8 -*-
 import argparse
 import google.protobuf.text_format as tf
@@ -240,7 +240,7 @@
 
     if output == '-':
         # std output
-        print java_code
+        print(java_code)
     else:
         with open(output, 'w') as output_file:
             output_file.write(java_code)
diff --git a/tools/dev/bin/onos-split-logs b/tools/dev/bin/onos-split-logs
index 687019d..065d804 100755
--- a/tools/dev/bin/onos-split-logs
+++ b/tools/dev/bin/onos-split-logs
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Splits ONOS DEBUG logs by partition/session for debugging consistent primitives.
 # When logs are split, this script will create a separate log file for each partition
 # and each Atomix session, e.g. karaf.log.partition-1, karaf.log.session-10, etc.
diff --git a/tools/dev/mininet/examples/ha.py b/tools/dev/mininet/examples/ha.py
index 18f1222..1ec6932 100755
--- a/tools/dev/mininet/examples/ha.py
+++ b/tools/dev/mininet/examples/ha.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 """
 NOTES
@@ -196,13 +196,13 @@
     def start( self ):
         output( "(starting HTTP Server)" )
         # start python web server as a bg process
-        self.cmd( 'python -m SimpleHTTPServer &> web.log &' )
+        self.cmd( 'python3 -m SimpleHTTPServer &> web.log &' )
 
     def stop( self ):
         # XXX is this ever called?
-        print "Stopping HTTP Server..."
-        print self.cmd( 'fg' )
-        print self.cmd( '\x03' )  # ctrl-c
+        print("Stopping HTTP Server...")
+        print(self.cmd( 'fg' ))
+        print(self.cmd( '\x03' ))  # ctrl-c
 
 
 class DynamicONOSNode( onos.ONOSNode ):
@@ -278,7 +278,7 @@
                 l.rotate( -1 )
             return perms
 
-        print "Generating %s with %s" % ( location, str(nodes) )
+        print("Generating %s with %s" % ( location, str(nodes) ))
         port = 9876
         ips = [ node.IP() for node in nodes ]
         node = lambda k: { 'id': k, 'ip': k, 'port': port }
@@ -411,7 +411,7 @@
         for node in cluster.activeNodes:
             node.shouldStart = True
     else:
-        print "Incorrect test"
+        print("Incorrect test")
         return
     net.start()
     if args.interactive:
diff --git a/tools/dev/mininet/examples/multicluster.py b/tools/dev/mininet/examples/multicluster.py
index 29e2b56..1ad7c5b 100755
--- a/tools/dev/mininet/examples/multicluster.py
+++ b/tools/dev/mininet/examples/multicluster.py
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+#!/usr/bin/python3
 """
 multicluster.py: multiple ONOS clusters example
 
@@ -85,7 +84,7 @@
         cmap.setdefault( c, [] ).append( s.name )
     for c in sorted( cmap.keys() ):
         switches = ' '.join( cmap[ c ] )
-        print '%s: %s' % ( c, switches )
+        print('%s: %s' % ( c, switches ))
 
 ONOSCLI.do_controllers = do_controllers
 
diff --git a/tools/dev/mininet/onos.py b/tools/dev/mininet/onos.py
index f8e3703..8e22e5b 100755
--- a/tools/dev/mininet/onos.py
+++ b/tools/dev/mininet/onos.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 
 """
 onos.py: ONOS cluster and control network in Mininet
@@ -113,7 +113,7 @@
     # Get rid of stale junk
     for var in 'ONOS_CELL', 'ONOS_INSTANCES':
         env[ var ] = ''
-    for var in environ.keys():
+    for var in list(environ.keys()):
         if var.startswith( 'OC' ):
             env[ var ] = ''
     for index, node in enumerate( nodes, 1 ):
@@ -285,7 +285,7 @@
 
     def intfsDown( self ):
         """Bring all interfaces down"""
-        for intf in self.intfs.values():
+        for intf in list(self.intfs.values()):
             cmdOutput = intf.ifconfig( 'down' )
             # no output indicates success
             if cmdOutput:
@@ -293,7 +293,7 @@
 
     def intfsUp( self ):
         """Bring all interfaces up"""
-        for intf in self.intfs.values():
+        for intf in list(self.intfs.values()):
             cmdOutput = intf.ifconfig( 'up' )
             if cmdOutput:
                 error( "Error setting %s up: %s " % ( intf.name, cmdOutput ) )
@@ -338,7 +338,7 @@
     def memAvailable( self ):
         "Return available memory in KB (or -1 if we can't tell)"
         lines = open( '/proc/meminfo' ).read().strip().split( '\n' )
-        entries = map( str.split, lines )
+        entries = list(map( str.split, lines ))
         index = { entry[ 0 ]: entry for entry in entries }
         # Check MemAvailable if present
         default = ( None, '-1', 'kB' )
@@ -411,7 +411,7 @@
         "Update environment variables"
         cmd = ';'.join( ( 'export %s="%s"' % ( var, val )
                           if val else 'unset %s' % var )
-                        for var, val in envDict.iteritems() )
+                        for var, val in envDict.items() )
         self.cmd( cmd )
 
     def ucmd( self, *args, **_kwargs ):
diff --git a/tools/dev/p4vm/install-p4-tools.sh b/tools/dev/p4vm/install-p4-tools.sh
index 4bc4e04..e3ca954 100755
--- a/tools/dev/p4vm/install-p4-tools.sh
+++ b/tools/dev/p4vm/install-p4-tools.sh
@@ -88,13 +88,13 @@
         libtool \
         make \
         pkg-config \
-        python2.7 \
-        python2.7-dev \
+        python3 \
+        python3-dev \
         tcpdump \
         wget \
         unzip
 
-    sudo -H pip2.7 install setuptools cffi ipaddr ipaddress pypcap \
+    sudo -H pip3 install setuptools cffi ipaddr ipaddress pypcap \
         git+https://github.com/p4lang/scapy-vxlan \
         git+https://github.com/p4lang/ptf.git
 }
@@ -150,8 +150,8 @@
     # Hack to get the -std=c++11 flag when building 3.6.1
     # https://github.com/protocolbuffers/protobuf/blob/v3.6.1/python/setup.py#L208
     export KOKORO_BUILD_NUMBER="hack"
-    sudo -E python2.7 setup.py build --cpp_implementation
-    sudo -E pip2.7 install .
+    sudo -E python3 setup.py build --cpp_implementation
+    sudo -E pip3 install .
     unset KOKORO_BUILD_NUMBER
 }
 
@@ -180,8 +180,8 @@
     sudo ldconfig
     unset LDFLAGS
 
-    sudo pip2.7 install -r requirements.txt
-    sudo pip2.7 install .
+    sudo pip3 install -r requirements.txt
+    sudo pip3 install .
 }
 
 function checkout_bmv2 {
diff --git a/tools/dev/p4vm/root-bootstrap.sh b/tools/dev/p4vm/root-bootstrap.sh
index e1b9449..6b3bab1 100755
--- a/tools/dev/p4vm/root-bootstrap.sh
+++ b/tools/dev/p4vm/root-bootstrap.sh
@@ -42,8 +42,8 @@
     git \
     git-review \
     htop \
-    python2.7 \
-    python2.7-dev \
+    python3 \
+    python3-dev \
     valgrind \
     zip unzip \
     tcpdump \
@@ -65,14 +65,11 @@
 
 rm -f corretto.deb
 
-rm -f /usr/bin/python
-ln -s `which python2.7` /usr/bin/python
-
 # Install pip and some python deps (others are defined in install-p4-tools.sh)
 curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
-python2.7 get-pip.py --force-reinstall
+python3 get-pip.py --force-reinstall
 rm -f get-pip.py
-pip2.7 install ipaddress
+pip3 install ipaddress
 
 if [[ ${VM_TYPE} = "dev" ]]
 then
diff --git a/tools/dev/p4vm/upload-ova.sh b/tools/dev/p4vm/upload-ova.sh
index 0b2cfd3..2dbd4b4 100755
--- a/tools/dev/p4vm/upload-ova.sh
+++ b/tools/dev/p4vm/upload-ova.sh
@@ -2,5 +2,5 @@
 
 VM_TYPE=${P4_VM_TYPE:-dev}
 
-python $ONOS_ROOT/tools/build/uploadToS3.py -f onos-p4-${VM_TYPE}.ova ./onos-p4-${VM_TYPE}.ova
+python3 $ONOS_ROOT/tools/build/uploadToS3.py -f onos-p4-${VM_TYPE}.ova ./onos-p4-${VM_TYPE}.ova
 
diff --git a/tools/dev/vagrant/ansible/roles/common/tasks/main.yml b/tools/dev/vagrant/ansible/roles/common/tasks/main.yml
index c9d4dc5..c8e406f 100644
--- a/tools/dev/vagrant/ansible/roles/common/tasks/main.yml
+++ b/tools/dev/vagrant/ansible/roles/common/tasks/main.yml
@@ -21,6 +21,6 @@
 
 - name: Installing python3-lxc
   pip:
-    name: lxc-python2
+    name: python3-lxc
     state: present
   tags: [common]
\ No newline at end of file
diff --git a/tools/dev/vagrant/ansible/vars/global_vars.yml b/tools/dev/vagrant/ansible/vars/global_vars.yml
index cba95ef..cef41d9 100644
--- a/tools/dev/vagrant/ansible/vars/global_vars.yml
+++ b/tools/dev/vagrant/ansible/vars/global_vars.yml
@@ -38,8 +38,8 @@
   - "git-review"
   - "lxc"
   - "lxc-dev"
-  - "python-dev"
-  - "python-pip"
+  - "python3-dev"
+  - "python3-pip"
   - "unzip"
   - "zip"
 
@@ -106,7 +106,7 @@
     user: "optical"
     pass: $6$rounds=656000$Fdw89xOiuYlJAKpi$dK6wqIVaJpn96XBxZbcwZbg2mAuPdGbNEUfJaLV1dqC/SFtdrNIWXjxCobIefy3AVMdgobZl9D3OACtt8LkTz/
     cell: "1node"
-    mininet_exec: sudo -E python /home/ubuntu/onos/tools/test/topos/opticalTest.py {{ lxc.lxc_one.ip }}
+    mininet_exec: sudo -E python3 /home/ubuntu/onos/tools/test/topos/opticalTest.py {{ lxc.lxc_one.ip }}
     lincoe_exec: sudo /home/ubuntu/linc-oe/rel/linc/bin/linc attach
     reset_exec: /home/ubuntu/reset-to-1.sh proxyarp,optical
     url: "https://wiki.onosproject.org/display/ONOS/Packet+Optical+Tutorial"
diff --git a/tools/package/karaf-assembly/onos-assembly.py b/tools/package/karaf-assembly/onos-assembly.py
index 1e394bf..fd0c49d 100755
--- a/tools/package/karaf-assembly/onos-assembly.py
+++ b/tools/package/karaf-assembly/onos-assembly.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 '''
   Builds synthetic feature file that includes all core, provider, and application
   features, so that we can pre-stage all bundles required to run ONOS off-line.
@@ -75,6 +75,6 @@
                 if level and (not elem.tail or not elem.tail.strip()):
                     elem.tail = i
 
-        print 'Writing to file:', outputFile
+        print('Writing to file:', outputFile)
         indent(outputTree)
         ET.dump(outputTree)
diff --git a/tools/package/onos_stage.py b/tools/package/onos_stage.py
index 9dc1973..d0143aa 100755
--- a/tools/package/onos_stage.py
+++ b/tools/package/onos_stage.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 """
  Copyright 2017-present Open Networking Foundation
 
diff --git a/tools/package/runtime/bin/_check-json b/tools/package/runtime/bin/_check-json
index 1eef25b..0ebaf2c 100644
--- a/tools/package/runtime/bin/_check-json
+++ b/tools/package/runtime/bin/_check-json
@@ -22,7 +22,7 @@
 # -----------------------------------------------------------------------------
 
 checkJson() {
-    cat ${1} | python -m json.tool >> /dev/null
+    cat ${1} | python3 -m json.tool >> /dev/null
     if [ "$?" -ne "0" ]; then
         echo "Not valid JSON File" && exit 1
     fi
diff --git a/tools/test/bin/atomix-gen-config b/tools/test/bin/atomix-gen-config
index c3c89ac..9b6efdd 100755
--- a/tools/test/bin/atomix-gen-config
+++ b/tools/test/bin/atomix-gen-config
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 """
 usage: atomix-gen-config [-h] [-s PARTITION_SIZE] [-n NUM_PARTITIONS]
                          [node_ip] [filename] [node_ip [node_ip ...]]
@@ -158,4 +158,4 @@
     with open(filename, 'w') as f:
       f.write(output)
   else:
-    print output
+    print(output)
diff --git a/tools/test/bin/onos-dist-verify b/tools/test/bin/onos-dist-verify
index b5e997f..f9de74e 100755
--- a/tools/test/bin/onos-dist-verify
+++ b/tools/test/bin/onos-dist-verify
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 """
 usage: onos-dist-verify [-h] [-n PRIMITIVE_NAME] [-p PARALLELISM]
                         [-c OPERATION_COUNT]
@@ -47,7 +47,7 @@
 try:
     import edn_format
 except ImportError:
-    print "No edn_format module found; use 'pip install edn_format'"
+    print("No edn_format module found; use 'pip install edn_format'")
     sys.exit(1)
 
 DEVNULL = open(os.devnull, 'w')
@@ -88,8 +88,8 @@
     node = nodes[0]
     try:
         subprocess.check_call(['onos', node, 'value-test', name, 'set', 'null'])
-    except subprocess.CalledProcessError, e:
-        print "Failed to reset test data"
+    except subprocess.CalledProcessError as e:
+        print("Failed to reset test data")
         sys.exit(1)
 
 
@@ -121,7 +121,7 @@
     try:
         knossos_path = os.environ['KNOSSOS_PATH']
     except KeyError:
-        print "KNOSSOS_PATH is not defined; skipping model checker"
+        print("KNOSSOS_PATH is not defined; skipping model checker")
     else:
         # Create and write a temporary file to be passed to the Knossos model checker.
         with NamedTemporaryFile(mode='w+', delete=False) as f:
@@ -133,12 +133,12 @@
             output = subprocess.check_output(['lein', 'run', '--model', 'cas-register', file_name], cwd=knossos_path)
             result = output.strip().split()[-1]
             if result == 'true':
-                print "\rHistory is linearizable! :-)"
+                print("\rHistory is linearizable! :-)")
                 exitcode = 0
             else:
-                print "\rHistory is not linearizable. :-("
+                print("\rHistory is not linearizable. :-(")
                 exitcode = 1
-        except subprocess.CalledProcessError, e:
+        except subprocess.CalledProcessError as e:
             exitcode = e.returncode
 
         # Remove the temporary file before exiting.
@@ -208,15 +208,14 @@
     def record(self, entry):
         """Records an entry in the history."""
         self.entries.append(entry)
-        print str(entry).strip() + '\r'
+        print(str(entry).strip() + '\r')
 
     def __str__(self):
         return edn_format.dumps([entry.format() for entry in self.entries])
 
 
-class HistoryEntry(object):
+class HistoryEntry(object, metaclass=ABCMeta):
     """History entry."""
-    __metaclass__ = ABCMeta
 
     @abstractmethod
     def format(self):
@@ -258,9 +257,8 @@
         ])
 
 
-class Runnable(object):
+class Runnable(object, metaclass=ABCMeta):
     """Base class for managing the lifecycle of a threaded test process."""
-    __metaclass__ = ABCMeta
 
     def __init__(self):
         self.thread = None
@@ -439,7 +437,7 @@
             try:
                 self.disruptors.append(getattr(self, name))
             except AttributeError:
-                print "Unknown disruptor %s" % (name,)
+                print("Unknown disruptor %s" % (name,))
                 sys.exit(1)
 
     def run(self):
diff --git a/tools/test/bin/onos-distributed-manager b/tools/test/bin/onos-distributed-manager
index 0d3b1c3..22a2da1 100755
--- a/tools/test/bin/onos-distributed-manager
+++ b/tools/test/bin/onos-distributed-manager
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 """
  Copyright 2017-present Open Networking Foundation
  Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,7 @@
 import subprocess
 import sys
 import os
-from httplib import OK, NOT_FOUND, BAD_REQUEST
+from http.client import OK, NOT_FOUND, BAD_REQUEST
 from subprocess import Popen
 
 from flask import Flask, jsonify, request
@@ -98,7 +98,7 @@
                 file.write(json.dumps(config))
                 file.close()
         except Exception as error:
-            print error
+            print(error)
             sys.exit()
 
     def load_from_file(self):
@@ -115,7 +115,7 @@
         pagereturn += "<br><h3> Status of Added controllers  </h3><br>"
         pagereturn += " Id,&emsp; Ip,&emsp; Port,&emsp; Is Active <br> "
 
-        for key in self.cluster_config["nodes"].keys():
+        for key in list(self.cluster_config["nodes"].keys()):
             pagereturn += self.cluster_config["nodes"][key]["id"] + ",&emsp; " + \
                           self.cluster_config["nodes"][key]["ip"] + ",&emsp; " + \
                           str(self.cluster_config["nodes"][key]["port"]) + ",&emsp; "
diff --git a/tools/test/bin/onos-gen-config b/tools/test/bin/onos-gen-config
index b73df39..e214d2f 100755
--- a/tools/test/bin/onos-gen-config
+++ b/tools/test/bin/onos-gen-config
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 """
 usage: onos-gen-config [-h] [-s PARTITION_SIZE] [-n NUM_PARTITIONS]
                             [filename] [node_ip [node_ip ...]]
@@ -87,7 +87,7 @@
 
     args = parser.parse_args()
     node = args.node
-    print node
+    print(node)
     filename = args.filename
     nodes = get_nodes(args.nodes)
 
@@ -106,4 +106,4 @@
         with open(filename, 'w') as f:
             f.write(output)
     else:
-        print output
+        print(output)
diff --git a/tools/test/bin/onos-gen-default-cluster b/tools/test/bin/onos-gen-default-cluster
index e557eda..dc0522d 100755
--- a/tools/test/bin/onos-gen-default-cluster
+++ b/tools/test/bin/onos-gen-default-cluster
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 """
 usage: onos-gen-default-cluster [-h] [-s PARTITION_SIZE] [-n NUM_PARTITIONS]
                             [filename] [node_ip [node_ip ...]]
@@ -91,4 +91,4 @@
         with open(filename, 'w') as f:
             f.write(output)
     else:
-        print output
+        print(output)
diff --git a/tools/test/bin/onos-generate-activate-all-scenario b/tools/test/bin/onos-generate-activate-all-scenario
index e55758f..5a3b8bf 100755
--- a/tools/test/bin/onos-generate-activate-all-scenario
+++ b/tools/test/bin/onos-generate-activate-all-scenario
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python3
 
 import sys
 
@@ -67,7 +67,7 @@
 if len(sys.argv) > 1:
     app_list_file = sys.argv[1]
 else:
-    print "Usage: onos-generate-activate-all-scenario file-name-of-app-list"
+    print("Usage: onos-generate-activate-all-scenario file-name-of-app-list")
     sys.exit()
 
 with open(app_list_file) as apps:
@@ -90,5 +90,5 @@
 
 scenario = scenario + SCENARIO_FOOTER
 
-print scenario
+print(scenario)
 
diff --git a/tools/test/bin/onos-oecfg b/tools/test/bin/onos-oecfg
index e709ce3..021b668 100755
--- a/tools/test/bin/onos-oecfg
+++ b/tools/test/bin/onos-oecfg
@@ -9,4 +9,4 @@
 APP=onos-app-oecfg
 JAR=$M2_REPO/org/onosproject/$APP/$ONOS_POM_VERSION/$APP-$ONOS_POM_VERSION.jar
 
-java -jar $JAR < $1 | python -mjson.tool
+java -jar $JAR < $1 | python3 -mjson.tool
diff --git a/tools/test/bin/onos-set-up-minimal-apps b/tools/test/bin/onos-set-up-minimal-apps
index 1d450eb..11fa6a4 100755
--- a/tools/test/bin/onos-set-up-minimal-apps
+++ b/tools/test/bin/onos-set-up-minimal-apps
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 import subprocess
 import sys
diff --git a/tools/test/bin/onos-start-network b/tools/test/bin/onos-start-network
index e668b8d..86f3468 100755
--- a/tools/test/bin/onos-start-network
+++ b/tools/test/bin/onos-start-network
@@ -36,4 +36,4 @@
 $SCPCMD $ONOS_ROOT/tools/test/topos/* $ONOS_USER@[$OCN]:topos/
 
 echo "Starting Network."
-$SSHCMD -t $ONOS_USER@$OCN sudo python $topo $(env | sort | egrep "^OC[0-9]+" | cut -d= -f2)
+$SSHCMD -t $ONOS_USER@$OCN sudo python3 $topo $(env | sort | egrep "^OC[0-9]+" | cut -d= -f2)
diff --git a/tools/test/scenarios/bin/check-dhcp-netcfg.py b/tools/test/scenarios/bin/check-dhcp-netcfg.py
index c828c84..2786785 100755
--- a/tools/test/scenarios/bin/check-dhcp-netcfg.py
+++ b/tools/test/scenarios/bin/check-dhcp-netcfg.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 
 import requests
 import sys
@@ -6,7 +6,7 @@
 from requests.auth import HTTPBasicAuth
 
 if len(sys.argv) < 3:
-    print "usage: find-dhcp-netcfg onos-node name1=value1 ..."
+    print("usage: find-dhcp-netcfg onos-node name1=value1 ...")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -15,7 +15,7 @@
                           ':8181/onos/v1/network/configuration/apps/org.onosproject.dhcp',
                           auth=HTTPBasicAuth('onos', 'rocks'))
 
-print cfgRequest.text
+print(cfgRequest.text)
 
 if cfgRequest.status_code != 200:
     sys.exit(1)
@@ -32,8 +32,8 @@
     value = pair[1]
 
     if dhcp[name] != value:
-        print name + " differs: expected " + value + " but found " + dhcp[name]
-        print cfgJson
+        print(name + " differs: expected " + value + " but found " + dhcp[name])
+        print(cfgJson)
         sys.exit(1)
 
 
diff --git a/tools/test/scenarios/bin/check-masters.py b/tools/test/scenarios/bin/check-masters.py
index dfe4df6..9e68cad 100755
--- a/tools/test/scenarios/bin/check-masters.py
+++ b/tools/test/scenarios/bin/check-masters.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 
 import json
 import subprocess
@@ -6,7 +6,7 @@
 import time
 
 if len(sys.argv) != 2:
-    print "usage: check-masters {node}"
+    print("usage: check-masters {node}")
     sys.exit(1)
 
 node = sys.argv[1]
diff --git a/tools/test/scenarios/bin/create-flow.py b/tools/test/scenarios/bin/create-flow.py
index 9d709a0..a5bf9ba 100755
--- a/tools/test/scenarios/bin/create-flow.py
+++ b/tools/test/scenarios/bin/create-flow.py
@@ -1,5 +1,4 @@
-#! /usr/bin/env python
-
+#! /usr/bin/env python3
 import requests
 
 from requests.auth import HTTPBasicAuth
@@ -8,7 +7,7 @@
 
 
 if len(sys.argv) != 6:
-    print "usage: create-flow onos-node name device in-port out-port"
+    print("usage: create-flow onos-node name device in-port out-port")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -47,11 +46,11 @@
                               params=payload)
 
 if flowRequest.status_code != 201:
-    print flowRequest.text
+    print(flowRequest.text)
     sys.exit(1)
 
 location = flowRequest.headers["location"]
-print "@stc " + name + "Location=" + location
+print("@stc " + name + "Location=" + location)
 sys.exit(0)
 
 
diff --git a/tools/test/scenarios/bin/create-intent.py b/tools/test/scenarios/bin/create-intent.py
index 4e5d4f6..aeb2492 100755
--- a/tools/test/scenarios/bin/create-intent.py
+++ b/tools/test/scenarios/bin/create-intent.py
@@ -1,5 +1,4 @@
-#! /usr/bin/env python
-
+#! /usr/bin/env python3
 import requests
 
 from requests.auth import HTTPBasicAuth
@@ -8,7 +7,7 @@
 
 
 if len(sys.argv) != 7:
-    print "usage: create-intent onos-node name ingressDevice ingressPort egressDevice egressPort"
+    print("usage: create-intent onos-node name ingressDevice ingressPort egressDevice egressPort")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -38,11 +37,11 @@
                               data=intentJson)
 
 if intentRequest.status_code != 201:
-    print intentRequest.text
+    print(intentRequest.text)
     sys.exit(1)
 
 location = intentRequest.headers["location"]
-print "@stc " + name + "Location=" + location
+print("@stc " + name + "Location=" + location)
 sys.exit(0)
 
 
diff --git a/tools/test/scenarios/bin/delete-netcfg.py b/tools/test/scenarios/bin/delete-netcfg.py
index 6e309c2..410bc47 100755
--- a/tools/test/scenarios/bin/delete-netcfg.py
+++ b/tools/test/scenarios/bin/delete-netcfg.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 
 import requests
 
@@ -8,7 +8,7 @@
 
 
 if len(sys.argv) != 3:
-    print "usage: delete-netcfg onos-node config-name"
+    print("usage: delete-netcfg onos-node config-name")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -18,7 +18,7 @@
                               auth=HTTPBasicAuth('onos', 'rocks'))
 
 if intentRequest.status_code != 204:
-    print intentRequest.text
+    print(intentRequest.text)
     sys.exit(1)
 
 sys.exit(0)
diff --git a/tools/test/scenarios/bin/execute-tapi-context-get-call.py b/tools/test/scenarios/bin/execute-tapi-context-get-call.py
index 22b1f27..7ddee28 100755
--- a/tools/test/scenarios/bin/execute-tapi-context-get-call.py
+++ b/tools/test/scenarios/bin/execute-tapi-context-get-call.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 
 import requests
 import sys
@@ -7,14 +7,14 @@
 from requests.auth import HTTPBasicAuth
 
 if len(sys.argv) < 3:
-    print "usage: execute-tapi-context-get-call onos-node state"
+    print("usage: execute-tapi-context-get-call onos-node state")
     sys.exit(1)
 
 node = sys.argv[1]
 state = sys.argv[2] #if empty tapi context must be empty, if full it needs to contain all devices and ports
 
 if state != "empty" and len(sys.argv) == 3:
-    print "usage: execute-tapi-context-get-call onos-node full devices links ports"
+    print("usage: execute-tapi-context-get-call onos-node full devices links ports")
     sys.exit(1)
 
 request = 'http://' + node + ':8181/onos/restconf/data/tapi-common:context'
@@ -23,9 +23,9 @@
 if state == "empty":
     uuid = tapiContext['tapi-common:context']['tapi-topology:topology-context']['topology'][0]['uuid']
     if uuid == "":
-        print "empty uuid"
+        print("empty uuid")
         sys.exit(1)
-    print "@stc tapi topology uuid=" + uuid
+    print("@stc tapi topology uuid=" + uuid)
     sys.exit(0)
 
 if state == "full":
@@ -37,11 +37,11 @@
     port_num = 0
     for x in range(dev_num):
         port_num=port_num+len(tapiContext['tapi-common:context']['tapi-topology:topology-context']['topology'][0]['node'][x]['owned-node-edge-point'])
-    print "device\tlink\tport\n%i\t%i\t%i" % (dev_num, directed_link_num/2, port_num)
+    print("device\tlink\tport\n%i\t%i\t%i" % (dev_num, directed_link_num/2, port_num))
     assert devices == dev_num
     assert links == directed_link_num/2
     assert ports == port_num
-    print "Topology infomation checking passed."
+    print("Topology infomation checking passed.")
     sys.exit(0)
 
 sys.exit(1)
diff --git a/tools/test/scenarios/bin/execute-tapi-delete-call.py b/tools/test/scenarios/bin/execute-tapi-delete-call.py
index aa9abfc..f2cfbfe 100755
--- a/tools/test/scenarios/bin/execute-tapi-delete-call.py
+++ b/tools/test/scenarios/bin/execute-tapi-delete-call.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 
 import sys
 import tapiHelper
@@ -6,16 +6,16 @@
 import requests
 
 if len(sys.argv) != 3 and len(sys.argv) != 4:
-    print "usage: execute-tapi-delete-call <onos-node> <deletion-type> [uuid]"
-    print "\t- <onos-node> is onos IP. 'localhost' is invalid."
-    print "\t- <deletion-type> is one of {line, client, both}, which mean line-side deletion, " \
-          "client-side deletion, and all deletion respectively."
-    print "\t- [uuid] is the created service uuid, which is optional. If uuid is empty, " \
-          "all connectivity services with <deletion-type> will be deleted."
-    print "\t  If [uuid] is not empty, and <deletion-type> is 'both', this script doesn't work."
-    print "\t  Otherwise, delete line-side or client-side connectivity with specific uuid."
-    print "For example, if we want to delete all client-side services on local host, the command should be:"
-    print "\t python execute-tapi-delete-call.py 127.0.0.1 client"
+    print("usage: execute-tapi-delete-call <onos-node> <deletion-type> [uuid]")
+    print("\t- <onos-node> is onos IP. 'localhost' is invalid.")
+    print("\t- <deletion-type> is one of {line, client, both}, which mean line-side deletion, " \
+          "client-side deletion, and all deletion respectively.")
+    print("\t- [uuid] is the created service uuid, which is optional. If uuid is empty, " \
+          "all connectivity services with <deletion-type> will be deleted.")
+    print("\t  If [uuid] is not empty, and <deletion-type> is 'both', this script doesn't work.")
+    print("\t  Otherwise, delete line-side or client-side connectivity with specific uuid.")
+    print("For example, if we want to delete all client-side services on local host, the command should be:")
+    print("\t python3 execute-tapi-delete-call.py 127.0.0.1 client")
     sys.exit(1)
 
 
@@ -55,8 +55,8 @@
 #
 def post_deletion(service_uuid, del_request):
     delete_input_json = json.dumps(tapi_deletion_input(service_uuid))
-    print "\nThe json content of deletion operation for connectivity service is \n\t\t%s." % \
-          delete_input_json
+    print("\nThe json content of deletion operation for connectivity service is \n\t\t%s." % \
+          delete_input_json)
     headers = {'Content-type': 'application/json'}
     resp = requests.post(del_request, data=delete_input_json, headers=headers, auth=('onos', 'rocks'))
     if resp.status_code != 200:
@@ -79,7 +79,7 @@
 try:
     services = context["tapi-connectivity:connectivity-context"]["connectivity-service"]
 except KeyError:
-    print "Warning - there is no connectivity service in ONOS (%s)." % node
+    print("Warning - there is no connectivity service in ONOS (%s)." % node)
     sys.exit(0)
 # 3. handle deletion requests according to <deletion-type> and [uuid]
 if serv_uuid is None:
@@ -93,13 +93,13 @@
            ((del_type == "client" or del_type == "both") and tapiHelper.is_dsr_media(sip)):
             json_resp = post_deletion(service["uuid"], delete_request)
             del_num += 1
-            print "Returns json string for deletion operations is\n %s\n" % json_resp
+            print("Returns json string for deletion operations is\n %s\n" % json_resp)
     if del_num == 0:
-        print "Warning - there is no %s-side connectivity servicein ONOS (%s)." % (del_type, node)
+        print("Warning - there is no %s-side connectivity servicein ONOS (%s)." % (del_type, node))
 else:
     # If [uuid] is not empty, check the <deletion-type>
     if del_type == "both":
-        print "Error - The option 'both' is illegal when [uuid] is assigned."
+        print("Error - The option 'both' is illegal when [uuid] is assigned.")
     else:
         is_del = False
         for service in services:
@@ -110,7 +110,7 @@
                    (del_type == "client" and tapiHelper.is_dsr_media(sip)):
                     json_resp = post_deletion(service["uuid"], delete_request)
                     is_del = True
-                    print "Returns json string for deletion operations is\n %s\n" % json_resp
+                    print("Returns json string for deletion operations is\n %s\n" % json_resp)
                     break
         if not is_del:
-            print "Warning - Cannot find %s-side connectivity service with service uuid %s." % (del_type, serv_uuid)
+            print("Warning - Cannot find %s-side connectivity service with service uuid %s." % (del_type, serv_uuid))
diff --git a/tools/test/scenarios/bin/execute-tapi-post-call.py b/tools/test/scenarios/bin/execute-tapi-post-call.py
index f6d419a..a0fe4c7 100755
--- a/tools/test/scenarios/bin/execute-tapi-post-call.py
+++ b/tools/test/scenarios/bin/execute-tapi-post-call.py
@@ -1,16 +1,15 @@
-#! /usr/bin/env python
-
+#! /usr/bin/env python3
 import sys
 import tapiHelper
 import json
 
 if len(sys.argv) < 4:
-    print "usage: execute-tapi-post-call <onos-node> <context> <empty> [uuid]."
-    print "\t- If <empty> is \"empty\", it measn that it should be no devices, links or ports"
-    print "\t- Uuid is optional and defaults to empty"
-    print "\t- For example:\n\t\t- line-side connectivity creation: %s\n\t\t- client-side connectivity creation: %s" % \
-          ("python execute-tapi-post-call.py 127.0.0.1 tapi-connectivity:create-connectivity-service line-side",
-           "python execute-tapi-post-call.py 127.0.0.1 tapi-connectivity:create-connectivity-service client-side")
+    print("usage: execute-tapi-post-call <onos-node> <context> <empty> [uuid].")
+    print("\t- If <empty> is \"empty\", it measn that it should be no devices, links or ports")
+    print("\t- Uuid is optional and defaults to empty")
+    print("\t- For example:\n\t\t- line-side connectivity creation: %s\n\t\t- client-side connectivity creation: %s" % \
+          ("python3 execute-tapi-post-call.py 127.0.0.1 tapi-connectivity:create-connectivity-service line-side",
+           "python3 execute-tapi-post-call.py 127.0.0.1 tapi-connectivity:create-connectivity-service client-side"))
     sys.exit(1)
 
 node = sys.argv[1]
@@ -22,40 +21,40 @@
 else:
     uuid = sys.argv[4]
 # request example:
-# python execute-tapi-post-call.py localhost tapi-common:get-service-interface-point-list empty
+# python3 execute-tapi-post-call.py localhost tapi-common:get-service-interface-point-list empty
 if "get-connectivity-service-list" in context:
     connectivity_request = 'http://' + node + ':8181/onos/restconf/operations/' + context
     tapi_connection = tapiHelper.get_connection(connectivity_request, uuid)
     tapi_connection_json = tapi_connection.json()
-    print tapi_connection_json
+    print(tapi_connection_json)
     if not tapi_connection_json["tapi-connectivity:output"] and empty != "empty":
-       print "No connection was established"
+       print("No connection was established")
        sys.exit(0)
     if empty == "empty":
         if not tapi_connection_json["tapi-connectivity:output"]:
             sys.exit(0)
         else:
-            print "There exist some connectivities!!!"
+            print("There exist some connectivities!!!")
             sys.exit(1)
     if uuid == "":
         # verify empty connection
-        print tapi_connection_json
+        print(tapi_connection_json)
     elif uuid != "":
         # verify correct connection
         servs = tapi_connection_json["tapi-connectivity:output"]["service"]
         for s in range(len(servs)):
             if servs[s]['uuid'] == uuid:
-                print "Find service with uuid %s" % uuid
-                print servs[s]
+                print("Find service with uuid %s" % uuid)
+                print(servs[s])
                 sys.exit(0)
     else:
-        print "Invalid input for 3rd and 4th parameters."
+        print("Invalid input for 3rd and 4th parameters.")
         sys.exit(1)
     sys.exit(0)
 
 # test succeeds by using cmd:
-# python execute-tapi-post-call.py 127.0.0.1 tapi-connectivity:create-connectivity-service line-side
-# python execute-tapi-post-call.py 127.0.0.1 tapi-connectivity:create-connectivity-service client-side
+# python3 execute-tapi-post-call.py 127.0.0.1 tapi-connectivity:create-connectivity-service line-side
+# python3 execute-tapi-post-call.py 127.0.0.1 tapi-connectivity:create-connectivity-service client-side
 if "create-connectivity-service" in context:
     context_request = 'http://' + node + ':8181/onos/restconf/data/tapi-common:context'
     connectivity_request = 'http://' + node + ':8181/onos/restconf/operations/' + context
@@ -65,8 +64,8 @@
         tapi_connection = tapiHelper.create_client_connection(context_request, connectivity_request)
     else:
         raise NotImplementedError("Not Implementation for option %s." % empty)
-    print "\nThe request context is:\t%s." % context
-    print "\nThe return message of the request is:\n\t\t%s " % json.dumps(tapi_connection.json())
+    print("\nThe request context is:\t%s." % context)
+    print("\nThe return message of the request is:\n\t\t%s " % json.dumps(tapi_connection.json()))
     sys.exit(0)
 
 sys.exit(1)
diff --git a/tools/test/scenarios/bin/find-device.py b/tools/test/scenarios/bin/find-device.py
index 430e18a..f222742 100755
--- a/tools/test/scenarios/bin/find-device.py
+++ b/tools/test/scenarios/bin/find-device.py
@@ -1,13 +1,13 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 
 import requests
 import sys
-import urllib
+import urllib.request, urllib.parse, urllib.error
 
 from requests.auth import HTTPBasicAuth
 
 if len(sys.argv) != 4:
-    print "usage: find-device onos-node name device-id"
+    print("usage: find-device onos-node name device-id")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -15,21 +15,21 @@
 id = sys.argv[3]
 
 deviceRequest = requests.get('http://' + node + ':8181/onos/v1/devices/' +
-                             urllib.quote_plus(id),
+                             urllib.parse.quote_plus(id),
                              auth=HTTPBasicAuth('onos', 'rocks'))
 
 if deviceRequest.status_code != 200:
-    print deviceRequest.text
+    print(deviceRequest.text)
     sys.exit(1)
 
 deviceJson = deviceRequest.json()
 
-print "@stc " + name + "Id=" + deviceJson["id"]
-print "@stc " + name + "Type=" + deviceJson["type"]
-print "@stc " + name + "Available=" + str(deviceJson["available"])
+print("@stc " + name + "Id=" + deviceJson["id"])
+print("@stc " + name + "Type=" + deviceJson["type"])
+print("@stc " + name + "Available=" + str(deviceJson["available"]))
 channelId = deviceJson["annotations"]["channelId"]
 channelIdWords = channelId.split(':')
-print "@stc " + name + "IpAddress=" + channelIdWords[0]
+print("@stc " + name + "IpAddress=" + channelIdWords[0])
 
 sys.exit(0)
 
diff --git a/tools/test/scenarios/bin/find-flow.py b/tools/test/scenarios/bin/find-flow.py
index a2f2e4d..6d68020 100755
--- a/tools/test/scenarios/bin/find-flow.py
+++ b/tools/test/scenarios/bin/find-flow.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 
 import requests
 import sys
@@ -6,7 +6,7 @@
 from requests.auth import HTTPBasicAuth
 
 if len(sys.argv) != 4:
-    print "usage: find-flow onos-node name device-id"
+    print("usage: find-flow onos-node name device-id")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -17,7 +17,7 @@
                             auth=HTTPBasicAuth('onos', 'rocks'))
 
 if flowsRequest.status_code != 200:
-    print flowsRequest.text
+    print(flowsRequest.text)
     sys.exit(1)
 
 flowsJson = flowsRequest.json()
@@ -28,9 +28,9 @@
             if criterion["type"] == 'IN_PORT' and criterion["port"] > 0:
                 for instruction in flow["treatment"]["instructions"]:
                     if instruction["port"] > 0 and instruction["type"] == 'OUTPUT':
-                        print "@stc " + name + "FlowState=" + flow["state"]
-                        print "@stc " + name + "FlowId=" + flow["id"]
-                        print "@stc " + name + "FlowPort=" + str(instruction["port"])
+                        print("@stc " + name + "FlowState=" + flow["state"])
+                        print("@stc " + name + "FlowId=" + flow["id"])
+                        print("@stc " + name + "FlowPort=" + str(instruction["port"]))
                         sys.exit(0)
 
 sys.exit(1)
diff --git a/tools/test/scenarios/bin/find-host.py b/tools/test/scenarios/bin/find-host.py
index e87a409..4c3aea5 100755
--- a/tools/test/scenarios/bin/find-host.py
+++ b/tools/test/scenarios/bin/find-host.py
@@ -1,13 +1,12 @@
-#! /usr/bin/env python
-
+#! /usr/bin/env python3
 import requests
 import sys
-import urllib
+import urllib.request, urllib.parse, urllib.error
 
 from requests.auth import HTTPBasicAuth
 
 if len(sys.argv) != 4:
-    print "usage: find-host onos-node name device-id"
+    print("usage: find-host onos-node name device-id")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -15,18 +14,18 @@
 id = sys.argv[3]
 
 hostRequest = requests.get('http://' + node + ':8181/onos/v1/hosts/' +
-                           urllib.quote_plus(id),
+                           urllib.parse.quote_plus(id),
                            auth=HTTPBasicAuth('onos', 'rocks'))
 
 if hostRequest.status_code != 200:
-    print hostRequest.text
+    print(hostRequest.text)
     sys.exit(1)
 
 hostJson = hostRequest.json()
 
-print "@stc " + name + "Id=" + hostJson["id"]
-print "@stc " + name + "Mac=" + hostJson["mac"]
-print "@stc " + name + "IpAddress=" + hostJson["ipAddresses"][0]
+print("@stc " + name + "Id=" + hostJson["id"])
+print("@stc " + name + "Mac=" + hostJson["mac"])
+print("@stc " + name + "IpAddress=" + hostJson["ipAddresses"][0])
 
 sys.exit(0)
 
diff --git a/tools/test/scenarios/bin/find-link-in-cluster.py b/tools/test/scenarios/bin/find-link-in-cluster.py
index 928531f..1eb6832 100755
--- a/tools/test/scenarios/bin/find-link-in-cluster.py
+++ b/tools/test/scenarios/bin/find-link-in-cluster.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 
 import requests
 import sys
@@ -6,7 +6,7 @@
 from requests.auth import HTTPBasicAuth
 
 if len(sys.argv) != 9:
-    print "usage: find-link-in-cluster onos-node name cluster-id expected-length src-device-id src-port dst-device-id dst-port"
+    print("usage: find-link-in-cluster onos-node name cluster-id expected-length src-device-id src-port dst-device-id dst-port")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -24,29 +24,29 @@
                             auth=HTTPBasicAuth('onos', 'rocks'))
 
 if linksRequest.status_code != 200:
-    print linksRequest.text
+    print(linksRequest.text)
     sys.exit(1)
 
 linksJson = linksRequest.json()
 linksLength = len(linksJson["links"])
 
 if  linksLength != length:
-    print "Expected length {} but got {}".format(length, linksLength)
+    print("Expected length {} but got {}".format(length, linksLength))
     sys.exit(1)
 
 for link in linksJson["links"]:
     if srcDeviceId == link["src"]["device"] and srcPort == link["src"]["port"]:
         if dstDeviceId == link["dst"]["device"] and dstPort == link["dst"]["port"]:
-            print "@stc " + name + "SrcDevice=" + link["src"]["device"]
-            print "@stc " + name + "SrcPort=" + link["src"]["port"]
-            print "@stc " + name + "DstDevice=" + link["dst"]["device"]
-            print "@stc " + name + "DstPort=" + link["dst"]["port"]
-            print "@stc " + name + "Type=" + link["type"]
-            print "@stc " + name + "State=" + link["state"]
+            print("@stc " + name + "SrcDevice=" + link["src"]["device"])
+            print("@stc " + name + "SrcPort=" + link["src"]["port"])
+            print("@stc " + name + "DstDevice=" + link["dst"]["device"])
+            print("@stc " + name + "DstPort=" + link["dst"]["port"])
+            print("@stc " + name + "Type=" + link["type"])
+            print("@stc " + name + "State=" + link["state"])
             sys.exit(0)
 
-print "Could not find link from {}:{} to {}:{}"\
-    .format(srcDeviceId, srcPort, dstDeviceId, dstPort)
+print("Could not find link from {}:{} to {}:{}"\
+    .format(srcDeviceId, srcPort, dstDeviceId, dstPort))
 sys.exit(1)
 
 
diff --git a/tools/test/scenarios/bin/find-link.py b/tools/test/scenarios/bin/find-link.py
index 9ac6e35..6e83de7 100755
--- a/tools/test/scenarios/bin/find-link.py
+++ b/tools/test/scenarios/bin/find-link.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 
 import requests
 import sys
@@ -6,7 +6,7 @@
 from requests.auth import HTTPBasicAuth
 
 if len(sys.argv) != 7:
-    print "usage: find-link onos-node name src-device-id src-port dst-device-id dst-port"
+    print("usage: find-link onos-node name src-device-id src-port dst-device-id dst-port")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -22,7 +22,7 @@
                             auth=HTTPBasicAuth('onos', 'rocks'))
 
 if linksRequest.status_code != 200:
-    print linksRequest.text
+    print(linksRequest.text)
     sys.exit(1)
 
 linksJson = linksRequest.json()
@@ -30,12 +30,12 @@
 for link in linksJson["links"]:
     if srcDeviceId == link["src"]["device"]:
         if dstDeviceId == link["dst"]["device"]:
-            print "@stc " + name + "SrcDevice=" + link["src"]["device"]
-            print "@stc " + name + "SrcPort=" + link["src"]["port"]
-            print "@stc " + name + "DstDevice=" + link["dst"]["device"]
-            print "@stc " + name + "DstPort=" + link["dst"]["port"]
-            print "@stc " + name + "Type=" + link["type"]
-            print "@stc " + name + "State=" + link["state"]
+            print("@stc " + name + "SrcDevice=" + link["src"]["device"])
+            print("@stc " + name + "SrcPort=" + link["src"]["port"])
+            print("@stc " + name + "DstDevice=" + link["dst"]["device"])
+            print("@stc " + name + "DstPort=" + link["dst"]["port"])
+            print("@stc " + name + "Type=" + link["type"])
+            print("@stc " + name + "State=" + link["state"])
             sys.exit(0)
 
 sys.exit(1)
diff --git a/tools/test/scenarios/bin/find-topo-infrastructure.py b/tools/test/scenarios/bin/find-topo-infrastructure.py
index 6d1970f..de6a271 100755
--- a/tools/test/scenarios/bin/find-topo-infrastructure.py
+++ b/tools/test/scenarios/bin/find-topo-infrastructure.py
@@ -1,13 +1,13 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 
 import requests
 import sys
-import urllib
+import urllib.request, urllib.parse, urllib.error
 
 from requests.auth import HTTPBasicAuth
 
 if len(sys.argv) != 4:
-    print "usage: find-topo-infrastructure onos-node name connect-point"
+    print("usage: find-topo-infrastructure onos-node name connect-point")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -15,16 +15,16 @@
 id = sys.argv[3]
 
 infrastructureRequest = requests.get('http://' + node + ':8181/onos/v1/topology/infrastructure/' +
-                           urllib.quote_plus(id),
+                           urllib.parse.quote_plus(id),
                            auth=HTTPBasicAuth('onos', 'rocks'))
 
 if infrastructureRequest.status_code != 200:
-    print infrastructureRequest.text
+    print(infrastructureRequest.text)
     sys.exit(1)
 
 infrastructureJson = infrastructureRequest.json()
 
-print "@stc " + name + "Infrastructure=" + str(infrastructureJson["infrastructure"])
+print("@stc " + name + "Infrastructure=" + str(infrastructureJson["infrastructure"]))
 
 sys.exit(0)
 
diff --git a/tools/test/scenarios/bin/mininet-p4-trellis b/tools/test/scenarios/bin/mininet-p4-trellis
index db19cc4..e964d0f 100755
--- a/tools/test/scenarios/bin/mininet-p4-trellis
+++ b/tools/test/scenarios/bin/mininet-p4-trellis
@@ -19,7 +19,7 @@
     echo \"cd ~/routing/trellis && \
         sudo -E env PYTHONPATH=/tmp/bmv2_py STRATUM_ROOT=${stratumRoot} \
             ONOS_WEB_USER=$ONOS_WEB_USER ONOS_WEB_PASS=$ONOS_WEB_PASS \
-        python trellisp4.py --onos-ip $OC1 --agent stratum\" \
+        python3 trellisp4.py --onos-ip $OC1 --agent stratum\" \
     > ${trellisp4Sh} && chmod +x ${trellisp4Sh}
 "
 
diff --git a/tools/test/scenarios/bin/onos-change-device-portstate b/tools/test/scenarios/bin/onos-change-device-portstate
index bc69d98..2dfbc9a 100755
--- a/tools/test/scenarios/bin/onos-change-device-portstate
+++ b/tools/test/scenarios/bin/onos-change-device-portstate
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 
 import requests
 
@@ -8,7 +8,7 @@
 
 
 if len(sys.argv) != 5:
-    print "usage: change-device-portstate onos-node device-id port new_enabled_state"
+    print("usage: change-device-portstate onos-node device-id port new_enabled_state")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -23,7 +23,7 @@
                                data=payload)
 
 if change_request.status_code != 200:
-    print change_request.text
+    print(change_request.text)
     sys.exit(1)
 
 sys.exit(0)
diff --git a/tools/test/scenarios/bin/onos-find-and-check-map b/tools/test/scenarios/bin/onos-find-and-check-map
index b419ca1..46daf8c 100755
--- a/tools/test/scenarios/bin/onos-find-and-check-map
+++ b/tools/test/scenarios/bin/onos-find-and-check-map
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 # -----------------------------------------------------------------------------
 # Invokes the ONOS CLI and looks for a 'maps' entry with the given name
@@ -9,7 +9,7 @@
 import sys
 
 if len(sys.argv) != 4:
-    print "usage: onos-find-and-check-map onos-node map-name should-be-zero"
+    print("usage: onos-find-and-check-map onos-node map-name should-be-zero")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -23,8 +23,8 @@
     foundMapName = map["name"]
     foundMapSize = map["size"]
 
-    print foundMapName
-    print foundMapSize
+    print(foundMapName)
+    print(foundMapSize)
 
     if foundMapName == mapName:
         if (shouldBeZero == 'yes' and foundMapSize == 0) or \
diff --git a/tools/test/scenarios/bin/post-netcfg.py b/tools/test/scenarios/bin/post-netcfg.py
index 6104f2c..6c3dcbc 100755
--- a/tools/test/scenarios/bin/post-netcfg.py
+++ b/tools/test/scenarios/bin/post-netcfg.py
@@ -1,12 +1,11 @@
-#! /usr/bin/env python
-
+#! /usr/bin/env python3
 import requests
 
 from requests.auth import HTTPBasicAuth
 import sys
 
 if len(sys.argv) != 3:
-    print "usage: post-netcfg onos-node json-file-name"
+    print("usage: post-netcfg onos-node json-file-name")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -20,7 +19,7 @@
                         data=configJson)
 
 if request.status_code != 200:
-    print request.text
+    print(request.text)
     sys.exit(1)
 
 sys.exit(0)
diff --git a/tools/test/scenarios/bin/query-cluster.py b/tools/test/scenarios/bin/query-cluster.py
index 0cac7ac..8d356b3 100755
--- a/tools/test/scenarios/bin/query-cluster.py
+++ b/tools/test/scenarios/bin/query-cluster.py
@@ -1,13 +1,13 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 
 import requests
 import sys
-import urllib
+import urllib.request, urllib.parse, urllib.error
 
 from requests.auth import HTTPBasicAuth
 
 if len(sys.argv) != 4:
-    print "usage: query-cluster onos-node name cluster-number"
+    print("usage: query-cluster onos-node name cluster-number")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -19,15 +19,15 @@
                            auth=HTTPBasicAuth('onos', 'rocks'))
 
 if topoRequest.status_code != 200:
-    print topoRequest.text
+    print(topoRequest.text)
     sys.exit(1)
 
 topoJson = topoRequest.json()
 
-print "@stc " + name + "Id=" + str(topoJson["id"])
-print "@stc " + name + "DeviceCount=" + str(topoJson["deviceCount"])
-print "@stc " + name + "LinkCount=" + str(topoJson["linkCount"])
-print "@stc " + name + "Root=" + topoJson["root"]
+print("@stc " + name + "Id=" + str(topoJson["id"]))
+print("@stc " + name + "DeviceCount=" + str(topoJson["deviceCount"]))
+print("@stc " + name + "LinkCount=" + str(topoJson["linkCount"]))
+print("@stc " + name + "Root=" + topoJson["root"])
 
 sys.exit(0)
 
diff --git a/tools/test/scenarios/bin/query-topo.py b/tools/test/scenarios/bin/query-topo.py
index 9b81b4e..9ce89b0 100755
--- a/tools/test/scenarios/bin/query-topo.py
+++ b/tools/test/scenarios/bin/query-topo.py
@@ -1,13 +1,13 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 
 import requests
 import sys
-import urllib
+import urllib.request, urllib.parse, urllib.error
 
 from requests.auth import HTTPBasicAuth
 
 if len(sys.argv) != 3:
-    print "usage: query-topo onos-node name"
+    print("usage: query-topo onos-node name")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -17,15 +17,15 @@
                            auth=HTTPBasicAuth('onos', 'rocks'))
 
 if topoRequest.status_code != 200:
-    print topoRequest.text
+    print(topoRequest.text)
     sys.exit(1)
 
 topoJson = topoRequest.json()
 
-print "@stc " + name + "Time=" + str(topoJson["time"])
-print "@stc " + name + "Devices=" + str(topoJson["devices"])
-print "@stc " + name + "Links=" + str(topoJson["links"])
-print "@stc " + name + "Clusters=" + str(topoJson["clusters"])
+print("@stc " + name + "Time=" + str(topoJson["time"]))
+print("@stc " + name + "Devices=" + str(topoJson["devices"]))
+print("@stc " + name + "Links=" + str(topoJson["links"]))
+print("@stc " + name + "Clusters=" + str(topoJson["clusters"]))
 
 sys.exit(0)
 
diff --git a/tools/test/scenarios/bin/tapiHelper.py b/tools/test/scenarios/bin/tapiHelper.py
index 47fdd65..2f227ef 100755
--- a/tools/test/scenarios/bin/tapiHelper.py
+++ b/tools/test/scenarios/bin/tapiHelper.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 import requests
 import json
@@ -143,7 +143,7 @@
                 if service["end-point"][id]["service-interface-point"]["service-interface-point-uuid"] == sip_uuid:
                     return True
     except KeyError:
-        print "There is no line-side service in ONOS now."
+        print("There is no line-side service in ONOS now.")
     return False
 
 
@@ -239,7 +239,7 @@
             used_sip_uuids.add(service["end-point"][0]["service-interface-point"]["service-interface-point-uuid"])
             used_sip_uuids.add(service["end-point"][1]["service-interface-point"]["service-interface-point-uuid"])
     except KeyError:
-        print "There is no existed connectivity service inside ONOS."
+        print("There is no existed connectivity service inside ONOS.")
 
     # select the first available line-side service as bridge. If there is no available line-side service,
     # then only create a client-to-client service for src and dst node.
@@ -256,8 +256,8 @@
             if (client_src_sip_uuid not in used_sip_uuids) and (client_dst_sip_uuid not in used_sip_uuids):
                 # If there is no such client-side connection exists
                 # Create new client-side connection directly
-                print "Create client-side connection between %s and %s." % \
-                      (client_src_name["onos-cp"], client_dst_name["onos-cp"])
+                print("Create client-side connection between %s and %s." % \
+                      (client_src_name["onos-cp"], client_dst_name["onos-cp"]))
                 create_input_json = json.dumps(tapi_client_input((client_src_sip_uuid, client_dst_sip_uuid)))
                 resp = requests.post(url_connectivity, data=create_input_json, headers=headers,
                                      auth=('onos', 'rocks'))
@@ -286,10 +286,10 @@
         # None case means all client-side services exist.
         raise AssertionError("There is no available client-side service could be created.")
     else:
-        print "Create client-side services:"
-        print "\t- from %s to %s." % (empty_client_src_name["onos-cp"], empty_client_dst_name["onos-cp"])
-        print "This service should go through:"
-        print "\t- %s and %s." % (empty_src_name["onos-cp"], empty_dst_name["onos-cp"])
+        print("Create client-side services:")
+        print("\t- from %s to %s." % (empty_client_src_name["onos-cp"], empty_client_dst_name["onos-cp"]))
+        print("This service should go through:")
+        print("\t- %s and %s." % (empty_src_name["onos-cp"], empty_dst_name["onos-cp"]))
         create_input_json = json.dumps(tapi_client_input((empty_client_src_sip_uuid, empty_client_dst_sip_uuid)))
         resp = requests.post(url_connectivity, data=create_input_json, headers=headers,
                              auth=('onos', 'rocks'))
@@ -344,16 +344,16 @@
     # select randomly the src_sip_uuid and dst_sip_uuid with same connection id.
     src_onep, dst_onep, src_sip_uuid, dst_sip_uuid = parse_src_dst(topo)
     while is_port_used(src_sip_uuid, context["tapi-common:context"]["tapi-connectivity:connectivity-context"]):
-        print "Conflict occurs between randomly selected line-side link and existed ones."
+        print("Conflict occurs between randomly selected line-side link and existed ones.")
         src_onep, dst_onep, src_sip_uuid, dst_sip_uuid = parse_src_dst(topo)
 
-    print "\nBuild line-side connectivity:\n|Item|SRC|DST|\n|:--|:--|:--|\n|onos-cp|%s|%s|\n|connection id|%s|%s|\n|sip uuid|%s|%s|" % \
+    print("\nBuild line-side connectivity:\n|Item|SRC|DST|\n|:--|:--|:--|\n|onos-cp|%s|%s|\n|connection id|%s|%s|\n|sip uuid|%s|%s|" % \
           (src_onep["name"][2]["value"], dst_onep["name"][2]["value"],
            src_onep["name"][1]["value"], dst_onep["name"][1]["value"],
-           src_sip_uuid, dst_sip_uuid)
+           src_sip_uuid, dst_sip_uuid))
     create_input_json = json.dumps(tapi_line_input((src_sip_uuid, dst_sip_uuid)))
-    print "\nThe json content of creation operation for line-side connectivity service is \n\t\t%s." % \
-          create_input_json
+    print("\nThe json content of creation operation for line-side connectivity service is \n\t\t%s." % \
+          create_input_json)
     headers = {'Content-type': 'application/json'}
     resp = requests.post(url_connectivity, data=create_input_json, headers=headers, auth=('onos', 'rocks'))
     if resp.status_code != 200:
diff --git a/tools/test/scenarios/bin/verify-topo-devices.py b/tools/test/scenarios/bin/verify-topo-devices.py
index be834b9..fb7f929 100755
--- a/tools/test/scenarios/bin/verify-topo-devices.py
+++ b/tools/test/scenarios/bin/verify-topo-devices.py
@@ -1,13 +1,13 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 
 import requests
 import sys
-import urllib
+import urllib.request, urllib.parse, urllib.error
 
 from requests.auth import HTTPBasicAuth
 
 if len(sys.argv) != 5:
-    print "usage: verify-topo-links onos-node cluster-id first-index last-index"
+    print("usage: verify-topo-links onos-node cluster-id first-index last-index")
     sys.exit(1)
 
 node = sys.argv[1]
@@ -23,26 +23,26 @@
                            auth=HTTPBasicAuth('onos', 'rocks'))
 
 if topoRequest.status_code != 200:
-    print topoRequest.text
+    print(topoRequest.text)
     sys.exit(1)
 
 topoJson = topoRequest.json()
 
 for deviceIndex in range(first, last+1):
     lookingFor = "of:" + format(deviceIndex, '016x')
-    print lookingFor
+    print(lookingFor)
     for arrayIndex in range(0, len(topoJson["devices"])):
         device = topoJson["devices"][arrayIndex]
         if device == lookingFor:
             found = found + 1
-            print "Match found for " + device
+            print("Match found for " + device)
             break
 
 
 if found == last - first:
     sys.exit(0)
 
-print "Found " + str(found) + " matches, need " + str(last - first)
+print("Found " + str(found) + " matches, need " + str(last - first))
 sys.exit(2)
 
 
diff --git a/tools/test/scenarios/net-odtn-restconf.xml b/tools/test/scenarios/net-odtn-restconf.xml
index cbfba36..549c9b8 100644
--- a/tools/test/scenarios/net-odtn-restconf.xml
+++ b/tools/test/scenarios/net-odtn-restconf.xml
@@ -23,7 +23,7 @@
     <!-- Push the line-side connectivity service request -->
     <group name="Net-ODTN-Restconf.Line-side-test" requires="Net-ODTN-Restconf.Confirm-conn-empty">
       <step name="Net-ODTN-Restconf.Create-line-side" exec="${ONOS_SCENARIOS}/bin/execute-tapi-post-call.py ${OC1} tapi-connectivity:create-connectivity-service line-side"/>
-      <step name="Net-ODTN-Restconf.Check-line-side" requires="Net-ODTN-Restconf.Create-line-side" exec="${ONOS_SCENARIOS}/odtn/checkUntilSucc.sh 'python ${ONOS_SCENARIOS}/bin/execute-tapi-post-call.py+${OC1}+tapi-connectivity:get-connectivity-service-list+empty+|+grep+'tapi-connectivity:output'+|+grep+connection-uuid+-o+|+wc+-l' 1" />
+      <step name="Net-ODTN-Restconf.Check-line-side" requires="Net-ODTN-Restconf.Create-line-side" exec="${ONOS_SCENARIOS}/odtn/checkUntilSucc.sh 'python3 ${ONOS_SCENARIOS}/bin/execute-tapi-post-call.py+${OC1}+tapi-connectivity:get-connectivity-service-list+empty+|+grep+'tapi-connectivity:output'+|+grep+connection-uuid+-o+|+wc+-l' 1" />
       <step name="Net-ODTN-Restconf.Delete-line-conn" requires="Net-ODTN-Restconf.Check-line-side" exec="${ONOS_SCENARIOS}/bin/execute-tapi-delete-call.py ${OC1} line"/>
       <step name="Net-ODTN-Restconf.Confirm-conn-empty-2" requires="Net-ODTN-Restconf.Delete-line-conn" exec="${ONOS_SCENARIOS}/bin/execute-tapi-post-call.py ${OC1} tapi-connectivity:get-connectivity-service-list empty"/>
       <group name="Net-ODTN-Restconf.Verify-Logs" requires="Net-ODTN-Restconf.Confirm-conn-empty-2">
@@ -35,7 +35,7 @@
     <!-- Push the client-side connectivity service request -->
     <group name="Net-ODTN-Restconf.Client-side-test" requires="Net-ODTN-Restconf.Line-side-test" delay="10" >
       <step name="Net-ODTN-Restconf.Create-client-side" exec="${ONOS_SCENARIOS}/bin/execute-tapi-post-call.py ${OC1} tapi-connectivity:create-connectivity-service client-side"/>
-      <step name="Net-ODTN-Restconf.Check-client-side" requires="Net-ODTN-Restconf.Create-client-side" exec="${ONOS_SCENARIOS}/odtn/checkUntilSucc.sh 'python ${ONOS_SCENARIOS}/bin/execute-tapi-post-call.py+${OC1}+tapi-connectivity:get-connectivity-service-list+empty+|+grep+'tapi-connectivity:output'+|+grep+connection-uuid+-o+|+wc+-l' 1" />
+      <step name="Net-ODTN-Restconf.Check-client-side" requires="Net-ODTN-Restconf.Create-client-side" exec="${ONOS_SCENARIOS}/odtn/checkUntilSucc.sh 'python3 ${ONOS_SCENARIOS}/bin/execute-tapi-post-call.py+${OC1}+tapi-connectivity:get-connectivity-service-list+empty+|+grep+'tapi-connectivity:output'+|+grep+connection-uuid+-o+|+wc+-l' 1" />
       <step name="Net-ODTN-Restconf.Delete-client-conn" requires="Net-ODTN-Restconf.Check-client-side" exec="${ONOS_SCENARIOS}/bin/execute-tapi-delete-call.py ${OC1} both"/>
       <step name="Net-ODTN-Restconf.Confirm-conn-empty-3" requires="Net-ODTN-Restconf.Delete-client-conn" exec="${ONOS_SCENARIOS}/bin/execute-tapi-post-call.py ${OC1} tapi-connectivity:get-connectivity-service-list empty"/>
       <group name="Net-ODTN-Restconf.Verify-Logs-2" requires="Net-ODTN-Restconf.Confirm-conn-empty-3">
diff --git a/tools/test/tests/onos-distributed-manager-test b/tools/test/tests/onos-distributed-manager-test
index 029acbf..ac92f46 100755
--- a/tools/test/tests/onos-distributed-manager-test
+++ b/tools/test/tests/onos-distributed-manager-test
@@ -1,7 +1,7 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 
 import unittest
-from httplib import OK, BAD_REQUEST
+from http.client import OK, BAD_REQUEST
 
 import requests
 import json
diff --git a/tools/test/topos/attcli.py b/tools/test/topos/attcli.py
index 1945320..80bac6f 100644
--- a/tools/test/topos/attcli.py
+++ b/tools/test/topos/attcli.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 """
 CLI for test with AttMplsTopo
diff --git a/tools/test/topos/attmpls.py b/tools/test/topos/attmpls.py
index fedcb6c..b72e711 100644
--- a/tools/test/topos/attmpls.py
+++ b/tools/test/topos/attmpls.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 """
 """
diff --git a/tools/test/topos/bmv2-demo.py b/tools/test/topos/bmv2-demo.py
index 949fe0c..ab0e811 100755
--- a/tools/test/topos/bmv2-demo.py
+++ b/tools/test/topos/bmv2-demo.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 import os
 import sys
@@ -18,13 +18,13 @@
 JUMBO_MTU=9000
 
 if 'ONOS_ROOT' not in os.environ:
-    print "Environment var $ONOS_ROOT not set"
+    print("Environment var $ONOS_ROOT not set")
     exit()
 else:
     ONOS_ROOT = os.environ["ONOS_ROOT"]
     sys.path.append(ONOS_ROOT + "/tools/dev/mininet")
 if 'RUN_PACK_PATH' not in os.environ:
-    print "Environment var $RUN_PACK_PATH not set"
+    print("Environment var $RUN_PACK_PATH not set")
     exit()
 else:
     RUN_PACK_PATH = os.environ["RUN_PACK_PATH"]
@@ -130,14 +130,14 @@
         self.cmd("killall arping")
 
     def describe(self):
-        print "**********"
-        print self.name
-        print "default interface: %s\t%s\t%s" % (
+        print("**********")
+        print(self.name)
+        print("default interface: %s\t%s\t%s" % (
             self.defaultIntf().name,
             self.defaultIntf().IP(),
             self.defaultIntf().MAC()
-        )
-        print "**********"
+        ))
+        print("**********")
 
     def getInfiniteCmdBg(self, cmd, logfile="/dev/null", delay=1):
         return "(while [ -e {} ]; " \
@@ -227,7 +227,7 @@
             }
         }
 
-    print "Writing network config to %s" % TEMP_NETCFG_FILE
+    print("Writing network config to %s" % TEMP_NETCFG_FILE)
     with open(TEMP_NETCFG_FILE, 'w') as tempFile:
         json.dump(netcfg, tempFile, indent=4)
 
@@ -267,7 +267,7 @@
     net.build()
     net.start()
 
-    print "Network started"
+    print("Network started")
 
     # Always generate background pings.
     sleep(3)
@@ -275,7 +275,7 @@
         h1.startPingBg(h2)
         h2.startPingBg(h1)
 
-    print "Background ping started"
+    print("Background ping started")
 
     # Increase the MTU size for INT operation
     if args.pipeconf_id.endswith("int") or args.pipeconf_id.endswith("full"):
@@ -284,22 +284,22 @@
     for h in net.hosts:
         h.startIperfServer()
 
-    print "Iperf servers started"
+    print("Iperf servers started")
 
     if args.bg_traffic:
         sleep(4)
-        print "Starting iperf clients..."
+        print("Starting iperf clients...")
         net.hosts[0].startIperfClient(net.hosts[-1], flowBw="400k",
                                       numFlows=50, duration=10)
 
     generateNetcfg(onosIp, net, args)
 
     if args.netcfg_sleep > 0:
-        print "Waiting %d seconds before pushing config to ONOS..." \
-              % args.netcfg_sleep
+        print("Waiting %d seconds before pushing config to ONOS..." \
+              % args.netcfg_sleep)
         sleep(args.netcfg_sleep)
 
-    print "Pushing config to ONOS..."
+    print("Pushing config to ONOS...")
     call(("%s/onos-netcfg" % RUN_PACK_PATH, onosIp, TEMP_NETCFG_FILE))
 
     if not args.onos_ip:
diff --git a/tools/test/topos/default.py b/tools/test/topos/default.py
index b58b780..5525c92 100644
--- a/tools/test/topos/default.py
+++ b/tools/test/topos/default.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 """
 """
diff --git a/tools/test/topos/dual-onos.py b/tools/test/topos/dual-onos.py
index b0b92ed..a6e424a 100644
--- a/tools/test/topos/dual-onos.py
+++ b/tools/test/topos/dual-onos.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 from onosnet import run
 from dual import DualTopo
diff --git a/tools/test/topos/dual.py b/tools/test/topos/dual.py
index d795a37..3240173 100644
--- a/tools/test/topos/dual.py
+++ b/tools/test/topos/dual.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 """
 """
diff --git a/tools/test/topos/ectest.py b/tools/test/topos/ectest.py
index 37acfc5..7115bee 100755
--- a/tools/test/topos/ectest.py
+++ b/tools/test/topos/ectest.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 import json
 
@@ -54,34 +54,34 @@
         return self.__dId
 
     def getControllers(self, name=None):
-        return self.__cmap.values() if not name else self.__cmap.get(name)
+        return list(self.__cmap.values()) if not name else self.__cmap.get(name)
 
     def getSwitches(self, name=None):
-        return self.__smap.values() if not name else self.__smap.get(name)
+        return list(self.__smap.values()) if not name else self.__smap.get(name)
 
     def getHosts(self, name=None):
-        return self.__hmap.values() if not name else self.__hmap.get(name)
+        return list(self.__hmap.values()) if not name else self.__hmap.get(name)
 
     def injectInto(self, net):
         """ Adds available topology info to a supplied Mininet object. """
         # add switches, hosts, then links to mininet object
-        for sw, args in self.__switches.iteritems():
+        for sw, args in self.__switches.items():
             self.__smap[sw] = net.addSwitch(sw, **args)
-        for h, args in self.__hosts.iteritems():
+        for h, args in self.__hosts.items():
             self.__hmap[h] = net.addHost(h, **args)
-        for l, args in self.__links.iteritems():
+        for l, args in self.__links.items():
             src = self.__smap.get(l[0])
             dst = self.__smap.get(l[1])
             net.addLink(src if src else self.__hmap.get(l[0]),
                          dst if dst else self.__hmap.get(l[1]), **args)
         # then controllers
-        for c, args in self.__ctrls.iteritems():
+        for c, args in self.__ctrls.items():
             self.__cmap[c] = net.addController(c, **args)
 
     def start(self):
         """ starts the switches with the correct controller. """
-        map(lambda c: c.start(), self.__cmap.values())
-        map(lambda s: s.start(self.__cmap.values()), self.__smap.values())
+        list(map(lambda c: c.start(), list(self.__cmap.values())))
+        list(map(lambda s: s.start(list(self.__cmap.values())), list(self.__smap.values())))
 
     def build(self, *args):
         """ override for custom topology, similar to Topo """
@@ -193,7 +193,7 @@
 
     # fire everything up
     net.build()
-    map(lambda x: x.start(), domains)
+    list(map(lambda x: x.start(), domains))
 
     # create a minimal copy of the network for configuring LINC.
     cfgnet = Mininet()
@@ -226,7 +226,7 @@
     setLogLevel('info')
     import sys
     if len(sys.argv) < 4:
-        print ("Usage: sudo -E ./ectest.py ctl-set1 ... ctl-set4\n\n",
-                "Where ctl-set are comma-separated controller IP's")
+        print(("Usage: sudo -E ./ectest.py ctl-set1 ... ctl-set4\n\n",
+                "Where ctl-set are comma-separated controller IP's"))
     else:
         setup(sys.argv)
diff --git a/tools/test/topos/fractal.py b/tools/test/topos/fractal.py
index bc5c689..7590144 100755
--- a/tools/test/topos/fractal.py
+++ b/tools/test/topos/fractal.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 from mininet.topo import Topo
 
diff --git a/tools/test/topos/geant.py b/tools/test/topos/geant.py
index 6eedd29..25da34e 100644
--- a/tools/test/topos/geant.py
+++ b/tools/test/topos/geant.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 """
 """
diff --git a/tools/test/topos/gratuitousArp.py b/tools/test/topos/gratuitousArp.py
index 27af1e9..0fce183 100755
--- a/tools/test/topos/gratuitousArp.py
+++ b/tools/test/topos/gratuitousArp.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 import sys
 import os
 import fcntl
@@ -22,14 +22,14 @@
     try:
         sock.bind((intf, socket.SOCK_RAW))
     except:
-        print 'Device does not exist: %s' % intf
+        print('Device does not exist: %s' % intf)
         return
 
     if not ip:
         try:
             ip = getIPAddress(intf)
         except IOError:
-            print 'No IP for %s' % intf
+            print('No IP for %s' % intf)
             return
     packed_ip = pack('!4B', *[int(x) for x in ip.split('.')])
 
diff --git a/tools/test/topos/metro.py b/tools/test/topos/metro.py
index 76f4ed2..0ba7303 100755
--- a/tools/test/topos/metro.py
+++ b/tools/test/topos/metro.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 import json
 
@@ -53,34 +53,34 @@
         return self.__dId
 
     def getControllers(self, name=None):
-        return self.__cmap.values() if not name else self.__cmap.get(name)
+        return list(self.__cmap.values()) if not name else self.__cmap.get(name)
 
     def getSwitches(self, name=None):
-        return self.__smap.values() if not name else self.__smap.get(name)
+        return list(self.__smap.values()) if not name else self.__smap.get(name)
 
     def getHosts(self, name=None):
-        return self.__hmap.values() if not name else self.__hmap.get(name)
+        return list(self.__hmap.values()) if not name else self.__hmap.get(name)
 
     def injectInto(self, net):
         """ Adds available topology info to a supplied Mininet object. """
         # add switches, hosts, then links to mininet object
-        for sw, args in self.__switches.iteritems():
+        for sw, args in self.__switches.items():
             self.__smap[sw] = net.addSwitch(sw, **args)
-        for h, args in self.__hosts.iteritems():
+        for h, args in self.__hosts.items():
             self.__hmap[h] = net.addHost(h, **args)
-        for l, args in self.__links.iteritems():
+        for l, args in self.__links.items():
             src = self.__smap.get(l[0])
             dst = self.__smap.get(l[1])
             net.addLink(src if src else self.__hmap.get(l[0]),
                          dst if dst else self.__hmap.get(l[1]), **args)
         # then controllers
-        for c, args in self.__ctrls.iteritems():
+        for c, args in self.__ctrls.items():
             self.__cmap[c] = net.addController(c, **args)
 
     def start(self):
         """ starts the switches with the correct controller. """
-        map(lambda c: c.start(), self.__cmap.values())
-        map(lambda s: s.start(self.__cmap.values()), self.__smap.values())
+        list(map(lambda c: c.start(), list(self.__cmap.values())))
+        list(map(lambda s: s.start(list(self.__cmap.values())), list(self.__smap.values())))
 
     def build(self, *args):
         """ override for custom topology, similar to Topo """
@@ -216,7 +216,7 @@
 
     # fire everything up
     net.build()
-    map(lambda x: x.start(), domains)
+    list(map(lambda x: x.start(), domains))
 
     # create a minimal copy of the network for configuring LINC.
     cfgnet = Mininet()
@@ -249,7 +249,7 @@
     setLogLevel('info')
     import sys
     if len(sys.argv) < 5:
-        print ("Usage: sudo -E ./metro.py ctl-set1 ... ctl-set4\n\n",
-                "Where ctl-set are comma-separated controller IP's")
+        print(("Usage: sudo -E ./metro.py ctl-set1 ... ctl-set4\n\n",
+                "Where ctl-set are comma-separated controller IP's"))
     else:
         setup(sys.argv)
diff --git a/tools/test/topos/newFuncTopo.py b/tools/test/topos/newFuncTopo.py
index 5edf7f7..c3c6cbcf 100644
--- a/tools/test/topos/newFuncTopo.py
+++ b/tools/test/topos/newFuncTopo.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 """
 Custom topology for Mininet
diff --git a/tools/test/topos/obelisk.py b/tools/test/topos/obelisk.py
index fb6ccdb..3e96ee3 100755
--- a/tools/test/topos/obelisk.py
+++ b/tools/test/topos/obelisk.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 from mininet.topo import Topo
 
diff --git a/tools/test/topos/obeliskHostCheck.py b/tools/test/topos/obeliskHostCheck.py
index 988e2e5..92bc166 100755
--- a/tools/test/topos/obeliskHostCheck.py
+++ b/tools/test/topos/obeliskHostCheck.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 import sys
 import os
@@ -7,10 +7,10 @@
 # TODO: if none given, use OCI
 try:
     onosIp = sys.argv[1]
-    print "Reading hosts view from ONOS node " + onosIp + ":"
+    print("Reading hosts view from ONOS node " + onosIp + ":")
 except Exception as e:
-    print "Error reading ONOS IP arguement"
-    print e
+    print("Error reading ONOS IP arguement")
+    print(e)
 # Grab the json objects from ONOS
 output = os.popen("onos " + onosIp + " \"hosts -j\"" )
 hosts = json.loads( output.read() )
@@ -49,7 +49,7 @@
 
 if hosts or "Error" not in hosts:
     if hosts == []:
-        print "WARNING: There are no hosts discovered"
+        print("WARNING: There are no hosts discovered")
     else:
         for host in hosts:
             mac = None
@@ -73,19 +73,19 @@
                 # Now check if this matches where they should be
                 if mac and device and port:
                     if device != mappings[ str( mac ) ]:
-                        print "The attachment device is incorrect for host " + str( mac ) +\
-                              ". Expected: " + mappings[ str( mac ) ] + "; Actual: " + device
+                        print("The attachment device is incorrect for host " + str( mac ) +\
+                              ". Expected: " + mappings[ str( mac ) ] + "; Actual: " + device)
                         hostAttachment = False
                     if str( port ) != "1":
-                        print "The attachment port is incorrect for host " + str( mac ) +\
-                              ". Expected: 1; Actual: " + str( port)
+                        print("The attachment port is incorrect for host " + str( mac ) +\
+                              ". Expected: 1; Actual: " + str( port))
                         hostAttachment = False
                 else:
                     hostAttachment = False
             except AssertionError as e:
-                print "ERROR: Json object not as expected:"
-                print e
-                print "host object: " + repr( host )
+                print("ERROR: Json object not as expected:")
+                print(e)
+                print("host object: " + repr( host ))
                 hostAttachment = False
 else:
-    print "No hosts json output or \"Error\" in output. hosts = " + repr( hosts )
+    print("No hosts json output or \"Error\" in output. hosts = " + repr( hosts ))
diff --git a/tools/test/topos/onosnet.py b/tools/test/topos/onosnet.py
index adb4a10..223a585 100644
--- a/tools/test/topos/onosnet.py
+++ b/tools/test/topos/onosnet.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 import itertools
 import os
 import signal
@@ -137,7 +137,7 @@
         t -= 1
         sys.stdout.flush()
         sleep(1)
-    print
+    print()
 
 def formatBw( bw ):
     bw = float(bw)
@@ -221,7 +221,7 @@
 
 def run( topo, controllers=None, link=TCLink, autoSetMacs=True):
     if not topo:
-        print 'Need to provide a topology'
+        print('Need to provide a topology')
         exit(1)
 
     args = parse_args()
@@ -230,14 +230,14 @@
         controllers = args.ipAddrs
 
     if not controllers and args.clusterSize < 1:
-        print 'Need to provide a list of controller IPs, or define a cluster size.'
+        print('Need to provide a list of controller IPs, or define a cluster size.')
         exit( 1 )
 
     setLogLevel( 'info' )
 
     if args.clusterSize > 0:
         if 'ONOS_ROOT' not in os.environ:
-            print "Environment var $ONOS_ROOT not set (needed to import onos.py)"
+            print("Environment var $ONOS_ROOT not set (needed to import onos.py)")
             exit( 1 )
         sys.path.append(os.environ["ONOS_ROOT"] + "/tools/dev/mininet")
         from onos import ONOSCluster, ONOSOVSSwitch, ONOSCLI
diff --git a/tools/test/topos/opticalTest.py b/tools/test/topos/opticalTest.py
index 8e316fa..2f94747 100755
--- a/tools/test/topos/opticalTest.py
+++ b/tools/test/topos/opticalTest.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 from opticalUtils import MininetOE, LINCSwitch, LINCLink
 from mininet.topo import Topo
@@ -86,8 +86,8 @@
     if len( sys.argv ) >= 2:
         controllers = sys.argv[1:]
     else:
-        print 'Usage:sudo -E python opticalTest.py (<Controller IP>)+'
-        print 'Using localhost...\n'
+        print('Usage:sudo -E python3 opticalTest.py (<Controller IP>)+')
+        print('Using localhost...\n')
         controllers = [ '127.0.0.1' ]
 
     setLogLevel( 'info' )
diff --git a/tools/test/topos/opticalTestBig.py b/tools/test/topos/opticalTestBig.py
index b730c73..888a52d 100755
--- a/tools/test/topos/opticalTestBig.py
+++ b/tools/test/topos/opticalTestBig.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 from opticalUtils import MininetOE, LINCSwitch, LINCLink
 from mininet.topo import Topo
@@ -379,8 +379,8 @@
     if len( sys.argv ) >= 2:
         controllers = sys.argv[1:]
     else:
-        print 'Usage: sudo -E python opticalTestBig.py (<Controller IP>)+'
-        print 'Using localhost...\n'
+        print('Usage: sudo -E python3 opticalTestBig.py (<Controller IP>)+')
+        print('Using localhost...\n')
         controllers = [ '127.0.0.1' ]
 
     setLogLevel( 'info' )
diff --git a/tools/test/topos/opticalUtils.py b/tools/test/topos/opticalUtils.py
index ca01395..6eaf99d 100644
--- a/tools/test/topos/opticalUtils.py
+++ b/tools/test/topos/opticalUtils.py
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+#!/usr/bin/python3
 '''
 Notes:
 
@@ -56,7 +55,7 @@
 import json
 import os
 from time import sleep
-import urllib2
+import urllib.request, urllib.error, urllib.parse
 
 from mininet.node import Switch, OVSSwitch, RemoteController
 from mininet.topo import Topo
@@ -87,7 +86,7 @@
                     switch_id += 1
         return dpids_to_ids
     except:
-        print "Error working with {}\nError: {}\n".format(sysConfig, sys.exc_info())
+        print("Error working with {}\nError: {}\n".format(sysConfig, sys.exc_info()))
         fd.close()
         return None
 
@@ -114,7 +113,7 @@
     annotations.setdefault('name', switch.name)
     configDict[ 'annotations' ] = annotations
     ports = []
-    for port, intf in switch.intfs.items():
+    for port, intf in list(switch.intfs.items()):
         if intf.name == 'lo':
             continue
         portDict = {}
@@ -330,7 +329,7 @@
         self.configDict[ 'annotations' ].setdefault('name', self.name)
         self.configDict[ 'type' ] = self.switchType
         self.configDict[ 'ports' ] = []
-        for port, intf in self.intfs.items():
+        for port, intf in list(self.intfs.items()):
             if intf.name == 'lo':
                 continue
             else:
@@ -358,7 +357,7 @@
             fd.write(command)
             fd.close()
         except:
-            print "Error working with {}\nError: {}\n".format(self.writePipe, sys.exc_info())
+            print("Error working with {}\nError: {}\n".format(self.writePipe, sys.exc_info()))
             if fd:
                 fd.close()
 
@@ -553,26 +552,26 @@
         url = 'http://%s:8181/onos/v1/devices' % LINCSwitch.controllers[0].ip
         time = 0
         # Set up password authentication
-        pw_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
+        pw_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
         pw_mgr.add_password(None, url, LINCSwitch.restUser, LINCSwitch.restPass)
-        handler = urllib2.HTTPBasicAuthHandler(pw_mgr)
-        opener = urllib2.build_opener(handler)
+        handler = urllib.request.HTTPBasicAuthHandler(pw_mgr)
+        opener = urllib.request.build_opener(handler)
         opener.open(url)
-        urllib2.install_opener(opener)
+        urllib.request.install_opener(opener)
         # focus on just checking the state of devices we're interested in
         # expected devices availability map
-        devMap =  dict.fromkeys(map( lambda x: x['uri'], devices ), False)
+        devMap =  dict.fromkeys([x['uri'] for x in devices], False)
         while True:
-            response = json.load(urllib2.urlopen(url))
+            response = json.load(urllib.request.urlopen(url))
             devs = response.get('devices')
 
             # update availability map
             for d in devs:
-                if devMap.has_key(d['id']):
+                if d['id'] in devMap:
                     devMap[d['id']] = d['available']
 
             # Check if all devices we're interested became available
-            if all(devMap.viewvalues()):
+            if all(devMap.values()):
                 break;
 
             if (time >= TIMEOUT):
@@ -612,7 +611,7 @@
             # Annotations hold switch name and latitude/longitude
             devDict = {}
             devDict[ 'type' ] = switch[ 'type' ]
-            devDict.update({k: v for k, v in switch[ 'annotations' ].iteritems() if k in BasicDevConfigKeys})
+            devDict.update({k: v for k, v in switch[ 'annotations' ].items() if k in BasicDevConfigKeys})
             devSubj = switch[ 'uri' ]
             devices[ devSubj ] = { 'basic': devDict }
 
diff --git a/tools/test/topos/regionabc-onos.py b/tools/test/topos/regionabc-onos.py
index f2c8218..9696b57 100644
--- a/tools/test/topos/regionabc-onos.py
+++ b/tools/test/topos/regionabc-onos.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 from onosnet import run
 from regionabc import RegionABC
diff --git a/tools/test/topos/regionabc.py b/tools/test/topos/regionabc.py
index 14aa9e7..be537f5 100644
--- a/tools/test/topos/regionabc.py
+++ b/tools/test/topos/regionabc.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 """
       [1] ----- [3] ----- [5]
diff --git a/tools/test/topos/rftest.py b/tools/test/topos/rftest.py
index 7aba54f..80807c7 100644
--- a/tools/test/topos/rftest.py
+++ b/tools/test/topos/rftest.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 import sys
 
@@ -35,6 +35,6 @@
     if len( sys.argv ) > 1:
         controllers = sys.argv[ 1: ]
     else:
-        print 'Usage: rf-test.py <c0 IP> <c1 IP> ...'
+        print('Usage: rf-test.py <c0 IP> <c1 IP> ...')
         exit( 1 )
     run( controllers )
diff --git a/tools/test/topos/rftesttopo.py b/tools/test/topos/rftesttopo.py
index 9b97578..205811a 100644
--- a/tools/test/topos/rftesttopo.py
+++ b/tools/test/topos/rftesttopo.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 """
 """
diff --git a/tools/test/topos/routinglib.py b/tools/test/topos/routinglib.py
index 6ac0932..c92e52f 100644
--- a/tools/test/topos/routinglib.py
+++ b/tools/test/topos/routinglib.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 """
 Libraries for creating L3 topologies with routing protocols.
@@ -45,7 +45,7 @@
         self.cmd('sysctl net.ipv4.ip_forward=1')
         self.cmd('sysctl net.ipv4.conf.all.rp_filter=0')
 
-        for intf, configs in self.interfaces.items():
+        for intf, configs in list(self.interfaces.items()):
             self.cmd('ip addr flush dev %s' % intf)
             self.cmd( 'sysctl net.ipv4.conf.%s.rp_filter=0' % intf )
             
@@ -99,9 +99,9 @@
         try:
             original_umask = os.umask(0)
             if (not os.path.isdir(QuaggaRouter.logDir)):
-                os.makedirs(QuaggaRouter.logDir, 0777)
+                os.makedirs(QuaggaRouter.logDir, 0o777)
             if (not os.path.isdir(self.runDir)):
-                os.makedirs(self.runDir, 0777)
+                os.makedirs(self.runDir, 0o777)
         finally:
             os.umask(original_umask)
 
@@ -182,8 +182,8 @@
         conf = ConfigurationWriter(self.configFile)
                     
         def getRouterId(interfaces):
-            intfAttributes = interfaces.itervalues().next()
-            print intfAttributes
+            intfAttributes = next(iter(interfaces.values()))
+            print(intfAttributes)
             if isinstance(intfAttributes, list):
                 # Try use the first set of attributes, but if using vlans they might not have addresses
                 intfAttributes = intfAttributes[1] if not intfAttributes[0]['ipAddrs'] else intfAttributes[0]
@@ -236,8 +236,8 @@
         conf = ConfigurationWriter(self.configFile)
             
         def getRouterId(interfaces):
-            intfAttributes = interfaces.itervalues().next()
-            print intfAttributes
+            intfAttributes = next(iter(interfaces.values()))
+            print(intfAttributes)
             if isinstance(intfAttributes, list):
                 # Try use the first set of attributes, but if using vlans they might not have addresses
                 intfAttributes = intfAttributes[1] if not intfAttributes[0]['ipAddrs'] else intfAttributes[0]
@@ -253,7 +253,7 @@
         conf.writeLine('ospf router-id %s' % getRouterId(self.qr.interfaces))
         conf.writeLine('!')
         
-        for name, intf in self.qr.interfaces.items():
+        for name, intf in list(self.qr.interfaces.items()):
             for ip in intf['ipAddrs']:
                 conf.writeLine('network %s area 0' % ip)
             #if intf['ipAddrs'][0].startswith('192.168'):
@@ -409,7 +409,7 @@
 
     @staticmethod
     def generatePeeringAddresses():
-        network = ip_network(u'10.0.%s.0/24' % AutonomousSystem.psIdx)
+        network = ip_network('10.0.%s.0/24' % AutonomousSystem.psIdx)
         AutonomousSystem.psIdx += 1
         
         return ip_interface('%s/%s' % (network[1], network.prefixlen)), \
@@ -456,7 +456,7 @@
         intfs = {}
         
         router = self.routers[1]
-        for i, router in self.routers.items():
+        for i, router in list(self.routers.items()):
         
             #routerName = 'r%i%i' % (self.num, i)
             routerName = 'r%i' % self.num
@@ -465,12 +465,12 @@
                 
             hostName = 'h%i' % self.num
         
-            for j, interface in router.interfaces.items():
+            for j, interface in list(router.interfaces.items()):
                 nativeAddresses = interface.addressesByVlan.pop(None, [])
                 peeringIntf = [{'mac' : '00:00:%02x:00:%02x:%02x' % (self.num, i, j),
                                'ipAddrs' : nativeAddresses}]
                 
-                for vlan, addresses in interface.addressesByVlan.items():
+                for vlan, addresses in list(interface.addressesByVlan.items()):
                     peeringIntf.append({'vlan':vlan,
                                         'mac':'00:00:%02x:%02x:%02x:%02x' % (self.num, vlan, i, j),
                                         'ipAddrs':addresses})
@@ -486,7 +486,7 @@
                 internalIntf = {'ipAddrs' : internalAddresses}
         
                 # This is the configuration of the next interface after all the peering interfaces
-                intfs.update({'%s-eth%s' % (routerName, len(router.interfaces.keys())) : internalIntf})
+                intfs.update({'%s-eth%s' % (routerName, len(list(router.interfaces.keys()))) : internalIntf})
     
             routerNode = topology.addHost(routerName,  
                                   asNum=self.asNum, neighbors=router.neighbors,
@@ -550,15 +550,15 @@
         self.peerIntfConfig = peerIntfConfig
         self.withFpm = withFpm
         self.externalOnos= externalOnos
-        self.internalPeeringSubnet = ip_network(u'1.1.1.0/24')
+        self.internalPeeringSubnet = ip_network('1.1.1.0/24')
         
-        for router in self.routers.values():
+        for router in list(self.routers.values()):
             # Add iBGP sessions to ONOS nodes
             for onosIp in onosIps:
                 router.neighbors.append({'address':onosIp, 'as':asNum, 'port':2000})
                 
             # Add iBGP sessions to other BGP speakers
-            for i, router2 in self.routers.items():
+            for i, router2 in list(self.routers.items()):
                 if router == router2:
                     continue
                 ip = AutonomousSystem.getIthAddress(self.internalPeeringSubnet, 10+i)
@@ -568,7 +568,7 @@
         
         natIp = AutonomousSystem.getLastAddress(self.internalPeeringSubnet)
         
-        for i, router in self.routers.items():
+        for i, router in list(self.routers.items()):
             name = 'bgp%s' % i
             
             ip = AutonomousSystem.getIthAddress(self.internalPeeringSubnet, 10+i)
@@ -580,7 +580,7 @@
                 eth1 = [{ 'mac':'00:00:00:00:00:%02x' % i, 
                          'ipAddrs' : nativeAddresses }]
                 
-                for vlan, addresses in router.interfaces[1].addressesByVlan.items():
+                for vlan, addresses in list(router.interfaces[1].addressesByVlan.items()):
                     eth1.append({'vlan':vlan,
                                 'mac':'00:00:00:%02x:%02x:00' % (i, vlan),
                                 'ipAddrs':addresses})
diff --git a/tools/test/topos/sdnip.py b/tools/test/topos/sdnip.py
index 7739d58..b561111 100755
--- a/tools/test/topos/sdnip.py
+++ b/tools/test/topos/sdnip.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 from mininet.cli import CLI
 from mininet.log import setLogLevel
@@ -65,26 +65,26 @@
         numRoutesPerAs = 32
 
         # Add external ASes
-        as1 = BasicAutonomousSystem(1, generateRoutes(u'192.168.1.0/24', numRoutesPerAs))
+        as1 = BasicAutonomousSystem(1, generateRoutes('192.168.1.0/24', numRoutesPerAs))
         AutonomousSystem.addPeering(as1, sdnAs)
         AutonomousSystem.addPeering(as1, sdnAs, router2=3, intf1=2)
         as1.addLink(s5)
         as1.addLink(s6)
         as1.build(self)
         
-        as2 = BasicAutonomousSystem(2, generateRoutes(u'192.168.2.0/24', numRoutesPerAs))
+        as2 = BasicAutonomousSystem(2, generateRoutes('192.168.2.0/24', numRoutesPerAs))
         AutonomousSystem.addPeering(as2, sdnAs)
         AutonomousSystem.addPeering(as2, sdnAs, router2=2)
         as2.addLink(s7)
         as2.build(self)
         
-        as3 = BasicAutonomousSystem(3, generateRoutes(u'192.168.3.0/24', numRoutesPerAs))
+        as3 = BasicAutonomousSystem(3, generateRoutes('192.168.3.0/24', numRoutesPerAs))
         AutonomousSystem.addPeering(as3, sdnAs, router2=2)
         AutonomousSystem.addPeering(as3, sdnAs, router2=3)
         as3.addLink(s8)
         as3.build(self)
         
-        as4 = BasicAutonomousSystem(4, generateRoutes(u'192.168.4.0/24', numRoutesPerAs), numRouters=2)
+        as4 = BasicAutonomousSystem(4, generateRoutes('192.168.4.0/24', numRoutesPerAs), numRouters=2)
         AutonomousSystem.addPeering(as4, sdnAs)
         AutonomousSystem.addPeering(as4, sdnAs, router1=2, router2=3)
         as4.addLink(s9)
diff --git a/tools/test/topos/sol.py b/tools/test/topos/sol.py
index 68f2d40..823fbe6 100755
--- a/tools/test/topos/sol.py
+++ b/tools/test/topos/sol.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 import sys, solar
 topo = solar.Solar(cips=sys.argv[1:])
 topo.run()
diff --git a/tools/test/topos/solar.py b/tools/test/topos/solar.py
index f316162..be3123a 100644
--- a/tools/test/topos/solar.py
+++ b/tools/test/topos/solar.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 from mininet.cli import CLI
 from mininet.net import Mininet
 from mininet.node import RemoteController, OVSKernelSwitch
diff --git a/tools/test/topos/topo b/tools/test/topos/topo
index 854de50..4ba951f 100755
--- a/tools/test/topos/topo
+++ b/tools/test/topos/topo
@@ -7,4 +7,4 @@
 topo=${1:-att-onos.py}
 
 [ -n "$1" ] && shift
-sudo python $topo "$@"
+sudo python3 $topo "$@"
diff --git a/tools/test/topos/tower.py b/tools/test/topos/tower.py
index 22d515b..02d2721 100755
--- a/tools/test/topos/tower.py
+++ b/tools/test/topos/tower.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 """
 """
diff --git a/tools/test/topos/uk-onos.py b/tools/test/topos/uk-onos.py
index 2426b4f..5202ee2 100644
--- a/tools/test/topos/uk-onos.py
+++ b/tools/test/topos/uk-onos.py
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+#!/usr/bin/python3
 from onosnet import run
 from uk import UkTopo
 
diff --git a/tools/test/topos/uk-region-onos.py b/tools/test/topos/uk-region-onos.py
index 744844d..214d2e8 100644
--- a/tools/test/topos/uk-region-onos.py
+++ b/tools/test/topos/uk-region-onos.py
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+#!/usr/bin/python3
 from onosnet import run
 from ukRegion import UkRegionTopo
 
diff --git a/tools/test/topos/uk.py b/tools/test/topos/uk.py
index aabd0b7..9bb5ec7 100644
--- a/tools/test/topos/uk.py
+++ b/tools/test/topos/uk.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 """
 """
diff --git a/tools/test/topos/ukRegion.py b/tools/test/topos/ukRegion.py
index ecbdf6a..af6c76b 100644
--- a/tools/test/topos/ukRegion.py
+++ b/tools/test/topos/ukRegion.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 """
   Sample network for demonstrating regions (see uk-region.json)
diff --git a/tools/test/topos/vpls.py b/tools/test/topos/vpls.py
index 0be2e68..8b3adf6 100755
--- a/tools/test/topos/vpls.py
+++ b/tools/test/topos/vpls.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 from mininet.cli import CLI
 from mininet.node import Link, Host
diff --git a/tools/tutorials/artemis/artemis-topo.py b/tools/tutorials/artemis/artemis-topo.py
index a612611..155108d6 100755
--- a/tools/tutorials/artemis/artemis-topo.py
+++ b/tools/tutorials/artemis/artemis-topo.py
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+#!/usr/bin/python3
 from mininet.topo import Topo
 from mininet.net import Mininet
 from mininet.cli import CLI
@@ -26,7 +25,7 @@
     def config(self, **kwargs):
         Host.config(self, **kwargs)
 
-        for intf, attrs in self.intfDict.items():
+        for intf, attrs in list(self.intfDict.items()):
             self.cmd('ip addr flush dev %s' % intf)
             if 'mac' in attrs:
                 self.cmd('ip link set %s down' % intf)
@@ -49,7 +48,7 @@
         Host.config(self, **kwargs)
         self.cmd('sysctl net.ipv4.ip_forward=1')
 
-        for intf, attrs in self.intfDict.items():
+        for intf, attrs in list(self.intfDict.items()):
             self.cmd('ip addr flush dev %s' % intf)
             if 'mac' in attrs:
                 self.cmd('ip link set %s down' % intf)
@@ -82,7 +81,7 @@
         Host.config(self, **kwargs)
         self.cmd('sysctl net.ipv4.ip_forward=1')
 
-        for intf, attrs in self.intfDict.items():
+        for intf, attrs in list(self.intfDict.items()):
             self.cmd('ip addr flush dev %s' % intf)
             if 'mac' in attrs:
                 self.cmd('ip link set %s down' % intf)
diff --git a/tools/tutorials/sdnip/tutorial.py b/tools/tutorials/sdnip/tutorial.py
index 316690e..7a66e6b 100755
--- a/tools/tutorials/sdnip/tutorial.py
+++ b/tools/tutorials/sdnip/tutorial.py
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+#!/usr/bin/python3
 from mininet.topo import Topo
 from mininet.net import Mininet
 from mininet.cli import CLI
@@ -36,7 +35,7 @@
         Host.config(self, **kwargs)
         self.cmd('sysctl net.ipv4.ip_forward=1')
 
-        for intf, attrs in self.intfDict.items():
+        for intf, attrs in list(self.intfDict.items()):
             self.cmd('ip addr flush dev %s' % intf)
             if 'mac' in attrs:
                 self.cmd('ip link set %s down' % intf)
diff --git a/tools/tutorials/sdnip/tutorial_ipv6.py b/tools/tutorials/sdnip/tutorial_ipv6.py
index c56579b..30645e8 100755
--- a/tools/tutorials/sdnip/tutorial_ipv6.py
+++ b/tools/tutorials/sdnip/tutorial_ipv6.py
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+#!/usr/bin/python3
 from mininet.topo import Topo
 from mininet.net import Mininet
 from mininet.cli import CLI
@@ -40,7 +39,7 @@
         self.cmd('sysctl net.ipv4.ip_forward=1')
         self.cmd('sysctl net.ipv6.conf.all.forwarding=1')
 
-        for intf, attrs in self.intfDict.items():
+        for intf, attrs in list(self.intfDict.items()):
             self.cmd('ip addr flush dev %s' % intf)
             if 'mac' in attrs:
                 self.cmd('ip link set %s down' % intf)