extras-buildsys/client client.py,1.26.2.1,1.26.2.2
Daniel Williams (dcbw)
fedora-extras-commits at redhat.com
Wed Aug 24 19:23:22 UTC 2005
Author: dcbw
Update of /cvs/fedora/extras-buildsys/client
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv31499/client
Modified Files:
Tag: STABLE_0_3
client.py
Log Message:
2005-08-24 Dan Williams <dcbw at redhat.com>
* common/BaseConfig.py
client/client.py
- Rewrite the client to make the code less stupid,
more easily followed, and to validate more
input options
- Also fixes RH #166692
Index: client.py
===================================================================
RCS file: /cvs/fedora/extras-buildsys/client/client.py,v
retrieving revision 1.26.2.1
retrieving revision 1.26.2.2
diff -u -r1.26.2.1 -r1.26.2.2
--- client.py 15 Aug 2005 14:33:05 -0000 1.26.2.1
+++ client.py 24 Aug 2005 19:23:20 -0000 1.26.2.2
@@ -18,6 +18,7 @@
import sys, os
from plague import XMLRPCServerProxy
+from plague import BaseConfig
import ConfigParser
import socket
import xmlrpclib
@@ -27,22 +28,29 @@
XMLRPC_API_VERSION = 1
-config = ConfigParser.ConfigParser()
-config.add_section('Certs')
-config.set('Certs', 'user-cert', '~/.fedora.cert')
-config.set('Certs', 'user-ca-cert', '~/.fedora-upload-ca.cert')
-config.set('Certs', 'server-ca-cert', '~/.fedora-server-ca.cert')
-
-config.add_section('Server')
-config.set('Server', 'use_ssl', 'True')
-config.set('Server', 'address', 'https://127.0.0.1:8887')
-
-config.add_section('User')
-config.set('User', 'email', 'foo at it.com')
+class ClientConfig(BaseConfig.BaseConfig):
+ def __init__(self, filename):
+ BaseConfig.BaseConfig.__init__(self, filename)
+ try:
+ self.open()
+ except BaseConfig.ConfigError, e:
+ print "Config file did not exist. Writing %s with default values. Error: %s" % (filename, e)
+ self.save_default_config()
+
+ def save_default_config(self, filename=None):
+ self.add_section("Certs")
+ self.set_option("Certs", "user-cert", "~/.fedora.cert")
+ self.set_option("Certs", "user-ca-cert", "~/.fedora-upload-ca.cert")
+ self.set_option("Certs", "server-ca-cert", "~/.fedora-server-ca.cert")
+
+ self.add_section("Server")
+ self.set_option("Server", "use_ssl", "yes")
+ self.set_option("Server", "address", "https://127.0.0.1:8887")
+ self.add_section("User")
+ self.set_option("User", "email", "foo at it.com")
-config_file_path = os.path.expanduser('~/.plague-client.cfg')
-config.read([config_file_path])
+ self.save()
class ServerException:
@@ -53,181 +61,215 @@
def __init__(self, message):
self.message = message
-
-def check_api_version(server):
- """ Ensure the API of the server matches the one we expect to talk to """
-
+def validate_jobid(jobid_in):
try:
- server_ver = server.api_version()
- except socket.error, e:
- print "Error connecting to build server: '%s'" % e
- return False
- except OpenSSL.SSL.SysCallError, e:
- print "Error connecting to build server: '%s'" % e
- return False
- except xmlrpclib.Fault, fault:
- print "Error: build server does not support 'api_version' method. Server said: '%s'" % fault
- return False
-
- if server_ver != XMLRPC_API_VERSION:
- print "Error: API version mismatch. Client: %d, Server: %d" % (XMLRPC_API_VERSION, server_ver)
- return False
+ jobid = int(jobid_in)
+ except ValueError:
+ raise CommandException("Invalid jobid.")
+ except TypeError:
+ raise CommandException("Invalid jobid.")
+ if jobid < 0:
+ raise CommandException("Invalid jobid.")
+ return jobid
+
+class PlagueClient:
+ def __init__(self, cfg_file):
+ self._cfg_file = cfg_file
+ self._cfg = ClientConfig(cfg_file)
+ self._email = self._get_user_email()
+ self._server = self._get_xmlrpc_server_proxy()
- return True
+ # Ensure the server's API version matches ours
+ self._check_api_version(self._server)
+ def _check_api_version(self, server):
+ """ Ensure the API of the server matches the one we expect to talk to """
+ try:
+ server_ver = server.api_version()
+ except socket.error, e:
+ raise ServerException("Error connecting to build server: '%s'" % e)
+ except OpenSSL.SSL.SysCallError, e:
+ raise ServerException("Error connecting to build server: '%s'" % e)
+ except xmlrpclib.Fault, fault:
+ raise ServerException("Error: build server does not support 'api_version' method. Server said: '%s'" % fault)
+
+ if server_ver != XMLRPC_API_VERSION:
+ raise ServerException("Error: API version mismatch. Client: %d, Server: %d" % (XMLRPC_API_VERSION, server_ver))
+
+ def _get_xmlrpc_server_proxy(self):
+ """
+ Return an XMLRPC server proxy object, either one that uses SSL with certificates
+ for verification, or one that doesn't do any authentication/encryption at all.
+ """
+ server = None
+ addr = self._cfg.get_str("Server", "address")
+ if self._cfg.get_bool("Server", "use_ssl"):
+ if addr.startswith("http:"):
+ raise ServerException("Error: '%s' is not an SSL server, but the use_ssl " \
+ " config option set to 'yes'. Fix %s" % (addr, self._cfg_file))
+ else:
+ certs = {}
+ certs['key_and_cert'] = os.path.expanduser(self._cfg.get_str('Certs', 'user-cert'))
+ certs['ca_cert'] = os.path.expanduser(self._cfg.get_str('Certs', 'user-ca-cert'))
+ certs['peer_ca_cert'] = os.path.expanduser(self._cfg.get_str('Certs', 'server-ca-cert'))
+ server = XMLRPCServerProxy.PlgXMLRPCServerProxy(addr, certs)
+ else:
+ if addr.startswith("https:"):
+ raise ServerException("Error: '%s' is an SSL server, but the use_ssl " \
+ "config option set to 'no'. Fix %s" % (addr, self._cfg_file))
+ else:
+ server = xmlrpclib.ServerProxy(addr)
+ return server
-def enqueue(server, email, args):
- """ Enqueue a package on the server by CVS tag """
-
- if len(args) != 3:
- raise CommandException("Invalid command. The 'enqueue' command only takes 3 arguments.")
- package = args[0]
- tag = args[1]
- target = args[2]
- use_ssl = config.get('Server', 'use_ssl')
- if use_ssl.lower() == 'true':
- (e, msg, uid) = server.enqueue(package, tag, target)
- else:
- (e, msg, uid) = server.enqueue(email, package, tag, target)
- if e == -1:
- print "Server returned an error: %s" % msg
- return
-
- if uid != -1:
- print "Package %s enqueued. Job ID: %d." % (package, uid)
- else:
- print "Package %s enqueued. (However, no Job ID was provided in the time required)" % package
-
-
-def enqueue_srpm(server, email, args):
- """ Enqueue a package on the server by SRPM """
-
- if len(args) != 3:
- raise CommandException("Invalid command. The 'enqueue_srpm' command only takes 3 arguments.")
- package = args[0]
- srpm = args[1]
- target = args[2]
- use_ssl = config.get('Server', 'use_ssl')
- if use_ssl.lower() == 'true':
- (e, msg, uid) = server.enqueue_srpm(package, srpm, target)
- else:
- (e, msg, uid) = server.enqueue_srpm(email, package, srpm, target)
- if e == -1:
- print "Server returned an error: %s" % msg
- return
-
- if uid != -1:
- print "Package %s enqueued. Job ID: %d." % (package, uid)
- else:
- print "Package %s enqueued. (However, no Job ID was provided in the time required)" % package
+ def _get_user_email(self):
+ """ Get email address either from certificate of config file """
+ cfg_email = self._cfg.get_str("User", "email")
+ if self._cfg.get_bool('Server', 'use_ssl'):
+ certfile = self._cfg.get_str('Certs', 'user-cert')
+ certfile = os.path.expanduser(certfile)
+ if not os.access(certfile, os.R_OK):
+ print "%s does not exist or is not readable." % certfile
+ sys.exit(1)
+ f = open(certfile, "r")
+ buf = f.read(8192)
+ f.close()
+ cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, buf)
+ cert_email = cert.get_subject().emailAddress
+ if cert_email != cfg_email:
+ print "Error: certificate's email address (%s) does not match the " \
+ "email address in %s (%s)." % (cert_email, self._cfg_file, cfg_email)
+ sys.exit(1)
+ return cfg_email
+
+ def _cmd_build(self, args):
+ if len(args) != 3:
+ raise CommandException("Invalid command. The 'build' command takes 3 arguments.")
+ package = args[0]
+ source = args[1]
+ target = args[2]
+ is_srpm = False
+ if source.endswith(".src.rpm"):
+ if not os.path.exists(source):
+ raise CommandException("The SRPM %s does not exist." % source)
+ is_srpm = True
+ self._enqueue(is_srpm, package, source, target)
+
+ def _enqueue(self, is_srpm, package, source, target):
+ """ Enqueue a package on the server by CVS tag """
+ use_ssl = self._cfg.get_bool("Server", "use_ssl")
+ if is_srpm:
+ if use_ssl:
+ (e, msg, jobid) = self._server.enqueue_srpm(package, source, target)
+ else:
+ (e, msg, jobid) = self._server.enqueue_srpm(self._email, package, source, target)
+ else:
+ if use_ssl:
+ (e, msg, jobid) = self._server.enqueue(package, source, target)
+ else:
+ (e, msg, jobid) = self._server.enqueue(self._email, package, source, target)
+ if e == -1:
+ print "Server returned an error: %s" % msg
+ return
-def requeue_job(server, email, uid):
- try:
- (e, msg) = server.requeue(uid)
- except socket.error, e:
- print "Error connecting to build server: '%s'" % e
- return
+ if jobid != -1:
+ print "Package %s enqueued. Job ID: %d." % (package, jobid)
+ else:
+ print "Package %s enqueued. (However, no Job ID was provided in the time required)" % package
- print msg
+ def _cmd_requeue(self, args):
+ if len(args) != 1:
+ raise CommandException("Invalid options.")
+ jobid = validate_jobid(args[0])
+ (e, msg) = self._server.requeue(jobid)
+ print msg
+ def _validate_list_opt(self, arg):
+ args = ['email', 'status', 'result', 'uid', 'uid_gt', 'uid_lt']
+ if arg in args:
+ return True
+ return False
-def validate_arg(arg):
- args = ['email', 'status', 'result', 'uid', 'uid_gt', 'uid_lt']
- if arg in args:
- return True
- return False
-
-def list_jobs(server, args):
- """
- List jobs by criteria
- """
-
- # Have to have an even number of options
- if int(len(args) / 2.0) != (len(args) / 2.0):
- print "Error: invalid options."
- return
-
- query_args = {}
- cmd = ''
- for arg in args:
- if not len(cmd):
- if validate_arg(arg):
- cmd = arg
+ def _cmd_list(self, args):
+ # Have to have an even number of options
+ if int(len(args) / 2.0) != (len(args) / 2.0):
+ raise CommandException("Invalid number of arguments.")
+
+ query_args = {}
+ cmd = ''
+ for arg in args:
+ if not len(cmd):
+ if self._validate_list_opt(arg):
+ cmd = arg
+ else:
+ raise CommandException("Error: invalid option '%s'" % arg)
else:
- print "Error: invalid option '%s'" % arg
- return
+ # 'status' call takes a sequence
+ if cmd == 'status':
+ arg = [arg]
+ # Validate options that take a jobid
+ if cmd == 'uid' or cmd == 'uid_lt' or cmd == 'uid_gt':
+ temp = validate_jobid(arg)
+ query_args[cmd] = arg
+ cmd = ''
+
+ if len(query_args) == 0:
+ # List all jobs
+ query_args['uid_gt'] = "0"
+
+ (e, msg, jobs) = self._server.list_jobs(query_args)
+ if e == -1:
+ print msg
+ elif len(jobs) == 0:
+ print "No jobs found that match the search criteria."
else:
- if cmd == 'status':
- arg = [arg]
- query_args[cmd] = arg
- cmd = ''
-
- if len(query_args) == 0:
- # List all jobs
- query_args['uid_gt'] = "0"
+ for job in jobs:
+ try:
+ print "%d: %s (%s) %s %s/%s" % (job['uid'], job['package'], job['source'], job['username'], job['status'], job['result'])
+ for archjob in job['archjobs']:
+ print "\t%s(%s): %s %s/%s" % (archjob['builder_addr'], archjob['arch'], archjob['jobid'], archjob['status'], archjob['builder_status'])
+ print ''
+ except IOError:
+ pass
+
+ def _cmd_detail(self, args):
+ if len(args) != 1:
+ raise CommandException("Invalid options.")
+ jobid = validate_jobid(args[0])
+ (e, msg, jobrec) = self._server.detail_job(jobid)
+ if e == -1:
+ print msg
+ return
+
+ print "\nDetail for Job ID %d (%s):" % (int(jobrec['uid']), jobrec['package'])
+ print "-" * 80
+ print "Source: %s" % jobrec['source']
+ print "Target: %s" % jobrec['target']
+ print "Submitter: %s" % jobrec['username']
+ try:
+ result = jobrec['result']
+ except KeyError:
+ result = ''
+ print "Status: %s/%s" % (jobrec['status'], result)
+
+ print "Archjobs:"
+ for aj in jobrec['archjobs']:
+ print " %s: %s %s/%s" % (aj['arch'], aj['builder_addr'], aj['status'], aj['builder_status'])
- try:
- (e, msg, jobs) = server.list_jobs(query_args)
- except socket.error, e:
- print "Error connecting to build server: '%s'" % e
- return
+ print ""
- if e == -1:
- print msg
- elif len(jobs) == 0:
- print "No jobs found that match the search criteria."
- else:
- for job in jobs:
- try:
- print "%d: %s (%s) %s %s/%s" % (job['uid'], job['package'], job['source'], job['username'], job['status'], job['result'])
- for archjob in job['archjobs']:
- print "\t%s(%s): %s %s/%s" % (archjob['builder_addr'], archjob['arch'], archjob['jobid'], archjob['status'], archjob['builder_status'])
- print ''
- except IOError:
- pass
-
-def detail_job(server, jobid):
- """
- Get a single job's details
- """
- try:
- (err, msg, jobrec) = server.detail_job(jobid)
- except socket.error, e:
- print "Error connecting to build server: '%s'" % e
- return
- if err == -1:
+ def _cmd_kill(self, args):
+ if len(args) != 1:
+ raise CommandException("Invalid options.")
+ jobid = validate_jobid(args[0])
+ (e, msg) = self._server.kill_job(self._email, jobid)
print msg
- return
-
- print "\nDetail for Job ID %d (%s):" % (int(jobrec['uid']), jobrec['package'])
- print "-" * 80
- print "Source: %s" % jobrec['source']
- print "Target: %s" % jobrec['target']
- print "Submitter: %s" % jobrec['username']
- print "Status: %s/%s" % (jobrec['status'], jobrec['result'])
-
- print "Archjobs:"
- for aj in jobrec['archjobs']:
- print " %s: %s %s/%s" % (aj['arch'], aj['builder_addr'], aj['status'], aj['builder_status'])
-
- print ""
-
-def kill(server, email, jobid):
- """
- Kill a job on the build server.
- """
-
- try:
- (err, msg) = server.kill_job(email, jobid)
- except socket.error, e:
- print "Error connecting to build server: '%s'" % e
- return
-
- print msg
+ def _print_builders(self, builder_list):
+ if len(builder_list) == 0:
+ print "No builders found."
+ return
-def print_builders(builder_list):
print "\nBuilders:"
print "-" * 90
for builder in builder_list:
@@ -240,132 +282,54 @@
print string
print ""
+ def _cmd_update_builders(self, args):
+ (e, msg, builder_list) = self._server.update_builders()
+ self._print_builders(builder_list)
+
+ def _cmd_list_builders(self, args):
+ (e, msg, builder_list) = self._server.list_builders()
+ self._print_builders(builder_list)
-def update_builders(server, email):
- """
- Tell the build server to requery its builder list ASAP.
- """
-
- try:
- (e, msg, builder_list) = server.update_builders()
- if len(builder_list) > 0:
- print_builders(builder_list)
- else:
- print "No builders found."
- except socket.error, e:
- print "Error connecting to build server: '%s'" % e
-
-
-def list_builders(server, email):
- """
- Get a list of currently active builders.
- """
-
- try:
- (e, msg, builder_list) = server.list_builders()
- if len(builder_list) > 0:
- print_builders(builder_list)
- else:
- print "No builders found."
- except socket.error, e:
- print "Error connecting to build server: '%s'" % e
-
-def pause(server, paused):
- """
- Pause or unpause the build server
- """
-
- try:
+ def _do_pause(self, paused):
(e, msg) = server.pause(paused)
print msg
- except socket.error, e:
- print "Error connecting to build server: '%s'" % e
+ def _cmd_pause(self, args):
+ self._do_pause(True)
-def is_paused(server):
- """
- Pause or unpause the build server
- """
+ def _cmd_unpause(self, args):
+ self._do_pause(False)
- try:
- if server.is_paused():
+ def _cmd_is_paused(self, args):
+ if self._server.is_paused():
print "The build server is paused."
else:
- print "The build server is _not_ paused."
- except socket.error, e:
- print "Error connecting to build server: '%s'" % e
+ print "The build server is not paused."
+ def _cmd_finish(self, args):
+ if len(args) == 0:
+ raise CommandException("Invalid options.")
+ jobid_list = []
+ for jobid in args:
+ int_jobid = validate_jobid(jobid)
+ jobid_list.append(int_jobid)
-def finish(server, args):
- uid_list = []
- for uid in args:
- uid_list.append(int(uid))
-
- try:
- (e, msg) = server.finish(uid_list)
- except socket.error, e:
- print "Error connecting to build server: '%s'" % e
-
- print msg
+ (e, msg) = self._server.finish(jobid_list)
+ print msg
-def getXMLRPCServerProxy(use_ssl):
- """
- Return an XMLRPC server proxy object, either one that uses SSL with certificates
- for verification, or one that doesn't do any authentication/encryption at all.
- """
-
- server = None
- addr = config.get('Server', 'address')
- use_ssl = use_ssl.lower()
- if use_ssl == 'true':
- if addr.startswith("http:"):
- raise ServerException("Error: '%s' is not an SSL server, but the use_ssl config option set to True. See %s" % (addr, config_file_path))
- else:
- certs = {}
- certs['key_and_cert'] = os.path.expanduser(config.get('Certs', 'user-cert'))
- certs['ca_cert'] = os.path.expanduser(config.get('Certs', 'user-ca-cert'))
- certs['peer_ca_cert'] = os.path.expanduser(config.get('Certs', 'server-ca-cert'))
- server = XMLRPCServerProxy.PlgXMLRPCServerProxy(addr, certs)
- elif use_ssl == 'false':
- if addr.startswith("https:"):
- raise ServerException("Error: '%s' is an SSL server, but the use_ssl config option set to False. See %s" % (addr, config_file_path))
- else:
- server = xmlrpclib.ServerProxy(addr)
- else:
- raise ServerException("Unrecognized value for config '%s' option use_ssl. See %s" % (use_ssl, config_file_path))
-
- return server
-
-
-def getEmailAddress():
- """ Get email address either from certificate of config file """
- config_email = config.get('User', 'email')
-
- use_ssl = config.get('Server', 'use_ssl')
- if use_ssl.lower() == 'true':
- certfile = config.get('Certs', 'user-cert')
- certfile = os.path.expanduser(certfile)
- if not os.access(certfile, os.R_OK):
- print "%s does not exist or is not readable." % certfile
- sys.exit(1)
- f = open(certfile, "r")
- buf = f.read(8192)
- f.close()
- cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, buf)
- cert_email = cert.get_subject().emailAddress
- if cert_email != config_email:
- print "Error: certificate's email address does not match the email address in the config file."
- sys.exit(1)
+ def dispatch(self, cmd, args):
+ try:
+ func = getattr(self, "_cmd_%s" % cmd)
+ func(args)
+ except AttributeError:
+ raise CommandException("Unknown command '%s'." % cmd)
- return config_email
def Usage():
print "Usage:\nplague-client.py <command>\n"
print " <command> is one of:"
- print " build [package_name] [cvs_tag | srpm_path] [target]"
- print " list"
- print " list <status>"
- print " list <email> <status>"
+ print " build <package_name> <cvs_tag | srpm_path> <target>"
+ print " list [email <addr>] [status <stat>] [result <result>] [uid <uid>]"
print " kill <jobid>"
print " update_builders"
print " list_builders"
@@ -383,67 +347,41 @@
Usage()
sys.exit(1)
- # Write out config file if it doesn't exist
- if not os.path.exists(config_file_path):
- f = open(config_file_path, "w+")
- config.write(f)
- f.close()
-
- cmd = sys.argv[1]
- email = getEmailAddress()
+ # Figure out the path of the config file. If the
+ # PLAGUE_CLIENT_CONFIG environment variable is set, use
+ # that. Otherwise, use ~/.plague-client.cfg
+ cfg_file = "~/.plague-client.cfg"
+ try:
+ cfg_file = os.environ['PLAGUE_CLIENT_CONFIG']
+ if not os.path.exists(cfg_file):
+ print "Config file specified in PLAUGE_CLIENT_CONFIG" \
+ " environment variable (%s) did not exist." % cfg_file
+ sys.exit(1)
+ except KeyError:
+ pass
try:
- server = getXMLRPCServerProxy(config.get('Server', 'use_ssl'))
+ cli = PlagueClient(os.path.expanduser(cfg_file))
except ServerException, e:
print e.message
sys.exit(1)
-
- # Ensure the server's API version matches ours
- if not check_api_version(server):
+ except BaseConfig.ConfigError, e:
+ print e
sys.exit(1)
- if cmd == 'build':
- if len(sys.argv) < 5:
+ try:
+ cmd = sys.argv[1]
+ if cmd == 'help':
Usage()
- sys.exit(1)
- item = sys.argv[3]
- try:
- if item.endswith(".src.rpm") and os.path.exists(item):
- enqueue_srpm(server, email, sys.argv[2:])
- else:
- enqueue(server, email, sys.argv[2:])
- except CommandException, e:
- print e.message
- elif cmd == 'requeue':
- jobid = sys.argv[2]
- requeue_job(server, email, jobid)
- elif cmd == 'list':
- list_jobs(server, sys.argv[2:])
- elif cmd == 'detail':
- detail_job(server, sys.argv[2])
- elif cmd == 'kill':
- if len(sys.argv) < 3:
- print "Error: need a job UID to kill"
- sys.exit(1)
- jobid = sys.argv[2]
- kill(server, email, jobid)
- elif cmd == 'update_builders':
- update_builders(server, email)
- elif cmd == 'list_builders':
- list_builders(server, email)
- elif cmd == 'pause':
- pause(server, True)
- elif cmd == 'unpause':
- pause(server, False)
- elif cmd == 'is_paused':
- is_paused(server)
- elif cmd == 'finish':
- finish(server, sys.argv[2:])
- elif cmd == 'help':
+ else:
+ cli.dispatch(cmd, sys.argv[2:])
+ except CommandException, e:
+ print e.message + "\n"
Usage()
sys.exit(1)
- else:
- print "Unknown command."
- Usage()
+ except socket.error, e:
+ print "Error connecting to build server: '%s'" % e
sys.exit(1)
+ sys.exit(0)
+
More information about the fedora-extras-commits
mailing list