Skip to content

Python 3 Upgrade #160

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
Aug 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
b9f8faa
Stage 1 fixes for restful-tango/*.py
fanpu Dec 27, 2019
f49a24d
Stage1 fix for tests/*.py
fanpu Dec 27, 2019
2fede95
Stage1 fix for jobManager
fanpu Dec 27, 2019
de0f03b
Stage1 fix for tango-cli.py
fanpu Dec 27, 2019
296c5ea
Remove accidentally committed .bak files
fanpu Dec 27, 2019
1ea7326
dictionary fixes
fanpu Mar 4, 2020
53dcf46
map fixes
fanpu Mar 4, 2020
b4fafcb
remapping for builtins semantics
fanpu Mar 4, 2020
d8b9da1
use standard library alises for refactored modules
fanpu Mar 4, 2020
3c8513d
urllib renamed modules
fanpu Mar 4, 2020
877c527
pasteurize newstyle for obj
fanpu Mar 4, 2020
5f95779
update packages
fanpu Apr 5, 2020
1fd770d
check and apply fix_unicode_keep_u fix
fanpu Mar 26, 2020
e2e6476
xrange fixes
fanpu Mar 26, 2020
0fa7c3a
downgrade tornado to be capped below 6
fanpu Apr 5, 2020
da74689
update tango dict to use new iter dict syntax
fanpu Apr 5, 2020
38cdda8
downgrade to tornado 4.x because 5.x has some new event loop requirem…
fanpu Apr 8, 2020
d270552
convert shell output to utf8
fanpu Apr 8, 2020
da9d68b
convert subprocess.check_output results to utf8
fanpu Apr 8, 2020
16a5f89
better error and unicode fixes
fanpu Apr 8, 2020
812f47f
rollback asyncio event loop
fanpu Apr 8, 2020
78520bf
get better perf by using hexists and to avoid getting bytes back
fanpu Apr 8, 2020
4e71932
remove accidental dbg
fanpu Apr 8, 2020
b75150f
specify append bytes for worker
fanpu Apr 12, 2020
7fd640b
convert redis keys output from bytes to string
fanpu Apr 12, 2020
28ddf89
convert request response to text
fanpu Apr 30, 2020
6398c7d
Skip over jobs that are None
fanpu May 14, 2020
9352903
More efficient native dict key lookup
fanpu Jul 6, 2020
b3462fb
Issue #153 fixes by changing &> to 2>&1
fanpu Jul 6, 2020
76d4215
apply correct fixes
fanpu Aug 14, 2020
86dbca8
ignore more ide files
fanpu Aug 14, 2020
a8f986b
list fix
fanpu Aug 14, 2020
0b13783
remove more usages of unnecessary list
fanpu Aug 14, 2020
4e630a9
remove more unnecessary list wraps
fanpu Aug 15, 2020
9feb851
Update README
fanpu Aug 19, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@ pip-selfcheck.json

# IDEs
.idea
.vscode

# Backup files
*.bak

6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ Please feel free to use Tango at your school/organization. If you run into any p
3. [Read the documentation for the VMMS API](https://github.com/autolab/Tango/wiki/Tango-VMMS-API).
4. [Test whether Tango is set up properly and can process jobs](https://github.com/autolab/Tango/wiki/Testing-Tango).

## Python 3 Upgrade
We are in the process of porting Tango from Python 2 to Python 3. The current working branch for the update is `python3-upgrade`.
## Python 2 Support
Tango now runs on Python 3. However, there is a legacy branch [master-python2](https://github.com/autolab/Tango/tree/master-python2) which is a snapshot of the last Python 2 Tango commit for legacy reasons. You are strongly encouraged to upgrade to the current Python 3 version of Tango if you are still on the Python 2 version, as future enhancements and bug fixes will be focused on the current master.

We will not be backporting new features from `master` to `master-python2`.

## Contributing to Tango

Expand Down
86 changes: 46 additions & 40 deletions clients/tango-cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
# tango-cli.py - Command line client for the RESTful Tango.
#

from __future__ import print_function
from builtins import range
from future import standard_library
standard_library.install_aliases()
from builtins import map
from builtins import str
import os
import sys

Expand All @@ -12,7 +18,7 @@
import argparse
import requests
import json
import urllib
import urllib.request, urllib.parse, urllib.error

#
#
Expand Down Expand Up @@ -95,35 +101,35 @@

def checkKey():
if (args.key is None):
print "Key must be specified with -k"
print("Key must be specified with -k")
return -1
return 0


def checkCourselab():
if (args.courselab is None):
print "Courselab must be specified with -l"
print("Courselab must be specified with -l")
return -1
return 0


def checkFilename():
if (args.filename is None):
print "Filename must be specified with --filename"
print("Filename must be specified with --filename")
return -1
return 0


def checkInfiles():
if (args.infiles is None):
print "Input files must be specified with --infiles"
print("Input files must be specified with --infiles")
return -1
return 0


def checkDeadjobs():
if (args.deadJobs is None):
print "Deadjobs must be specified with --deadJobs"
print("Deadjobs must be specified with --deadJobs")
return -1
return 0

Expand All @@ -139,11 +145,11 @@ def tango_open():
response = requests.get(
'http://%s:%d/open/%s/%s/' %
(args.server, args.port, args.key, args.courselab))
print "Sent request to %s:%d/open/%s/%s/" % (args.server, args.port, args.key, args.courselab)
print response.content
print("Sent request to %s:%d/open/%s/%s/" % (args.server, args.port, args.key, args.courselab))
print(response.text)

except Exception as err:
print "Failed to send request to %s:%d/open/%s/%s/" % (args.server, args.port, args.key, args.courselab)
print("Failed to send request to %s:%d/open/%s/%s/" % (args.server, args.port, args.key, args.courselab))
print (str(err))
sys.exit(0)

Expand All @@ -170,11 +176,11 @@ def tango_upload():
data=f.read(),
headers=header)
f.close()
print "Sent request to %s:%d/upload/%s/%s/ filename=%s" % (args.server, args.port, args.key, args.courselab, args.filename)
print response.content
print("Sent request to %s:%d/upload/%s/%s/ filename=%s" % (args.server, args.port, args.key, args.courselab, args.filename))
print(response.text)

except Exception as err:
print "Failed to send request to %s:%d/upload/%s/%s/ filename=%s" % (args.server, args.port, args.key, args.courselab, args.filename)
print("Failed to send request to %s:%d/upload/%s/%s/ filename=%s" % (args.server, args.port, args.key, args.courselab, args.filename))
print (str(err))
sys.exit(0)

Expand Down Expand Up @@ -208,11 +214,11 @@ def tango_addJob():
args.key,
args.courselab),
data=json.dumps(requestObj))
print "Sent request to %s:%d/addJob/%s/%s/ \t jobObj=%s" % (args.server, args.port, args.key, args.courselab, json.dumps(requestObj))
print response.content
print("Sent request to %s:%d/addJob/%s/%s/ \t jobObj=%s" % (args.server, args.port, args.key, args.courselab, json.dumps(requestObj)))
print(response.text)

except Exception as err:
print "Failed to send request to %s:%d/addJob/%s/%s/ \t jobObj=%s" % (args.server, args.port, args.key, args.courselab, json.dumps(requestObj))
print("Failed to send request to %s:%d/addJob/%s/%s/ \t jobObj=%s" % (args.server, args.port, args.key, args.courselab, json.dumps(requestObj)))
print (str(err))
sys.exit(0)

Expand All @@ -231,13 +237,13 @@ def tango_poll():
args.port,
args.key,
args.courselab,
urllib.quote(
urllib.parse.quote(
args.outputFile)))
print "Sent request to %s:%d/poll/%s/%s/%s/" % (args.server, args.port, args.key, args.courselab, urllib.quote(args.outputFile))
print response.content
print("Sent request to %s:%d/poll/%s/%s/%s/" % (args.server, args.port, args.key, args.courselab, urllib.parse.quote(args.outputFile)))
print(response.text)

except Exception as err:
print "Failed to send request to %s:%d/poll/%s/%s/%s/" % (args.server, args.port, args.key, args.courselab, urllib.quote(args.outputFile))
print("Failed to send request to %s:%d/poll/%s/%s/%s/" % (args.server, args.port, args.key, args.courselab, urllib.parse.quote(args.outputFile)))
print (str(err))
sys.exit(0)

Expand All @@ -252,11 +258,11 @@ def tango_info():

response = requests.get(
'http://%s:%d/info/%s/' % (args.server, args.port, args.key))
print "Sent request to %s:%d/info/%s/" % (args.server, args.port, args.key)
print response.content
print("Sent request to %s:%d/info/%s/" % (args.server, args.port, args.key))
print(response.text)

except Exception as err:
print "Failed to send request to %s:%d/info/%s/" % (args.server, args.port, args.key)
print("Failed to send request to %s:%d/info/%s/" % (args.server, args.port, args.key))
print (str(err))
sys.exit(0)

Expand All @@ -272,11 +278,11 @@ def tango_jobs():
response = requests.get(
'http://%s:%d/jobs/%s/%d/' %
(args.server, args.port, args.key, args.deadJobs))
print "Sent request to %s:%d/jobs/%s/%d/" % (args.server, args.port, args.key, args.deadJobs)
print response.content
print("Sent request to %s:%d/jobs/%s/%d/" % (args.server, args.port, args.key, args.deadJobs))
print(response.text)

except Exception as err:
print "Failed to send request to %s:%d/jobs/%s/%d/" % (args.server, args.port, args.key, args.deadJobs)
print("Failed to send request to %s:%d/jobs/%s/%d/" % (args.server, args.port, args.key, args.deadJobs))
print (str(err))
sys.exit(0)

Expand All @@ -291,11 +297,11 @@ def tango_pool():

response = requests.get('http://%s:%d/pool/%s/%s/' %
(args.server, args.port, args.key, args.image))
print "Sent request to %s:%d/pool/%s/%s/" % (args.server, args.port, args.key, args.image)
print response.content
print("Sent request to %s:%d/pool/%s/%s/" % (args.server, args.port, args.key, args.image))
print(response.text)

except Exception as err:
print "Failed to send request to %s:%d/pool/%s/%s/" % (args.server, args.port, args.key, args.image)
print("Failed to send request to %s:%d/pool/%s/%s/" % (args.server, args.port, args.key, args.image))
print (str(err))
sys.exit(0)

Expand All @@ -321,11 +327,11 @@ def tango_prealloc():
args.image,
args.num),
data=json.dumps(vmObj))
print "Sent request to %s:%d/prealloc/%s/%s/%s/ \t vmObj=%s" % (args.server, args.port, args.key, args.image, args.num, json.dumps(vmObj))
print response.content
print("Sent request to %s:%d/prealloc/%s/%s/%s/ \t vmObj=%s" % (args.server, args.port, args.key, args.image, args.num, json.dumps(vmObj)))
print(response.text)

except Exception as err:
print "Failed to send request to %s:%d/prealloc/%s/%s/%s/ \t vmObj=%s" % (args.server, args.port, args.key, args.image, args.num, json.dumps(vmObj))
print("Failed to send request to %s:%d/prealloc/%s/%s/%s/ \t vmObj=%s" % (args.server, args.port, args.key, args.image, args.num, json.dumps(vmObj)))
print (str(err))
sys.exit(0)

Expand All @@ -343,31 +349,31 @@ def file_to_dict(file):

def tango_runJob():
if args.runJob is None:
print "Invalid usage: [runJob]"
print("Invalid usage: [runJob]")
sys.exit(0)

dir = args.runJob
infiles = [file for file in os.listdir(
dir) if os.path.isfile(os.path.join(dir, file))]
files = [os.path.join(dir, file) for file in infiles]
args.infiles = map(file_to_dict, infiles)
args.infiles = list(map(file_to_dict, infiles))

args.jobname += "-0"
args.outputFile += "-0"
for i in xrange(1, args.numJobs + 1):
print "----------------------------------------- STARTING JOB " + str(i) + " -----------------------------------------"
print "----------- OPEN"
for i in range(1, args.numJobs + 1):
print("----------------------------------------- STARTING JOB " + str(i) + " -----------------------------------------")
print("----------- OPEN")
tango_open()
print "----------- UPLOAD"
print("----------- UPLOAD")
for file in files:
args.filename = file
tango_upload()
print "----------- ADDJOB"
print("----------- ADDJOB")
length = len(str(i - 1))
args.jobname = args.jobname[:-length] + str(i)
args.outputFile = args.outputFile[:-length] + str(i)
tango_addJob()
print "--------------------------------------------------------------------------------------------------\n"
print("--------------------------------------------------------------------------------------------------\n")


def router():
Expand Down Expand Up @@ -403,7 +409,7 @@ def router():
try:
response = requests.get('http://%s:%d/' % (args.server, args.port))
except:
print 'Tango not reachable on %s:%d!\n' % (args.server, args.port)
print('Tango not reachable on %s:%d!\n' % (args.server, args.port))
sys.exit(0)

router()
3 changes: 2 additions & 1 deletion config.template.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
# config.py - Global configuration constants and runtime info
#

from builtins import object
import logging, time

# Config - defines


class Config:
class Config(object):
#####
# Part 1: Tango constants for developers
#
Expand Down
14 changes: 13 additions & 1 deletion jobManager.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import print_function
#
# JobManager - Thread that assigns jobs to worker threads
#
Expand All @@ -9,6 +10,10 @@
# is launched that will handle things from here on. If anything goes
# wrong, the job is made dead with the error.
#
from builtins import object
from future import standard_library
standard_library.install_aliases()
from builtins import str
import threading, logging, time, copy

from datetime import datetime
Expand All @@ -20,7 +25,7 @@
from tangoObjects import TangoQueue
from config import Config

class JobManager:
class JobManager(object):

def __init__(self, queue):
self.daemon = True
Expand Down Expand Up @@ -62,9 +67,16 @@ def __manage(self):

if id:
job = self.jobQueue.get(id)

# job could no longer exist if it was completed by someone else
if job == None:
continue

if not job.accessKey and Config.REUSE_VMS:
id, vm = self.jobQueue.getNextPendingJobReuse(id)
job = self.jobQueue.get(id)
if job == None:
continue

try:
# Mark the job assigned
Expand Down
11 changes: 7 additions & 4 deletions jobQueue.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
# JobManager: Class that creates a thread object that looks for new
# work on the job queue and assigns it to workers.
#
from builtins import range
from builtins import object
from builtins import str
import threading, logging, time

from datetime import datetime
Expand All @@ -28,7 +31,7 @@
#


class JobQueue:
class JobQueue(object):

def __init__(self, preallocator):
self.liveJobs = TangoDictionary("liveJobs")
Expand All @@ -53,7 +56,7 @@ def _getNextID(self):
keys = self.liveJobs.keys()
if (str(id) in keys):
id = -1
for i in xrange(1, Config.MAX_JOBID + 1):
for i in range(1, Config.MAX_JOBID + 1):
if (str(i) not in keys):
id = i
break
Expand Down Expand Up @@ -191,7 +194,7 @@ def getNextPendingJob(self):
Called by JobManager when Config.REUSE_VMS==False
"""
self.queueLock.acquire()
for id, job in self.liveJobs.iteritems():
for id, job in self.liveJobs.items():
if job.isNotAssigned():
self.queueLock.release()
return id
Expand All @@ -203,7 +206,7 @@ def getNextPendingJobReuse(self, target_id=None):
Called by JobManager when Config.REUSE_VMS==True
"""
self.queueLock.acquire()
for id, job in self.liveJobs.iteritems():
for id, job in self.liveJobs.items():
# if target_id is set, only interested in this id
if target_id and target_id != id:
continue
Expand Down
4 changes: 3 additions & 1 deletion preallocator.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#
# preallocator.py - maintains a pool of active virtual machines
#
from builtins import object
from builtins import range
import threading, logging, time, copy

from tangoObjects import TangoDictionary, TangoQueue, TangoIntValue
Expand All @@ -17,7 +19,7 @@
#


class Preallocator:
class Preallocator(object):

def __init__(self, vmms):
self.machines = TangoDictionary("machines")
Expand Down
19 changes: 9 additions & 10 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
backports.ssl-match-hostname==3.4.0.2
boto==2.27.0
futures==2.2.0
plumbum==1.4.2
pyflakes==0.8.1
redis==2.10.3
requests==2.2.1
rpyc==3.3.0
wsgiref==0.1.2
tornado==4.1
backports.ssl-match-hostname==3.7.0.1
boto==2.49.0 # used only by ec2SSH.py
plumbum==1.6.9
pyflakes==2.1.1
redis==3.4.1
requests==2.23.0
rpyc==4.1.4
tornado==4.5.3
future==0.18.2
Loading