- update the interface between the kojivmd and kojikamid
- allow --specfile and --patches to be passed to the VM - handle validation of urls in kojivmd
This commit is contained in:
parent
0b485cd813
commit
38f74ed5a0
4 changed files with 84 additions and 38 deletions
89
vm/kojikamid
89
vm/kojikamid
|
|
@ -177,6 +177,7 @@ class SCM(object):
|
|||
sourcedir = '%s/%s' % (scmdir, self.module)
|
||||
|
||||
update_checkout_cmd = None
|
||||
update_checkout_dir = None
|
||||
|
||||
if self.scmtype == 'CVS':
|
||||
pserver = ':pserver:%s@%s:%s' % ((self.user or 'anonymous'), self.host, self.repository)
|
||||
|
|
@ -203,6 +204,7 @@ class SCM(object):
|
|||
sourcedir = '%s/%s' % (scmdir, checkout_path)
|
||||
module_checkout_cmd = ['git', 'clone', '-n', gitrepo, sourcedir]
|
||||
update_checkout_cmd = ['git', 'reset', '--hard', self.revision]
|
||||
update_checkout_dir = sourcedir
|
||||
|
||||
# self.module may be empty, in which case the specfile should be in the top-level directory
|
||||
if self.module:
|
||||
|
|
@ -222,6 +224,7 @@ class SCM(object):
|
|||
sourcedir = '%s/%s' % (scmdir, checkout_path)
|
||||
module_checkout_cmd = ['git', 'clone', '-n', gitrepo, sourcedir]
|
||||
update_checkout_cmd = ['git', 'reset', '--hard', self.revision]
|
||||
update_checkout_dir = sourcedir
|
||||
|
||||
# self.module may be empty, in which case the specfile should be in the top-level directory
|
||||
if self.module:
|
||||
|
|
@ -256,7 +259,7 @@ class SCM(object):
|
|||
if update_checkout_cmd:
|
||||
# Currently only required for GIT checkouts
|
||||
# Run the command in the directory the source was checked out into
|
||||
ret, output = run(update_checkout_cmd, chdir=sourcedir)
|
||||
ret, output = run(update_checkout_cmd, chdir=update_checkout_dir)
|
||||
log(output)
|
||||
if ret:
|
||||
raise BuildError, 'Error running %s update command "%s": %s' % \
|
||||
|
|
@ -332,18 +335,21 @@ class WindowsBuild(object):
|
|||
def log(msg):
|
||||
print >> sys.stderr, '%s: %s' % (datetime.datetime.now().ctime(), msg)
|
||||
|
||||
def run(cmd, chdir='.'):
|
||||
def run(cmd, chdir=None):
|
||||
shell = False
|
||||
if isinstance(cmd, (str, unicode)) and len(cmd.split()) > 1:
|
||||
shell = True
|
||||
olddir = os.getcwd()
|
||||
os.chdir(chdir)
|
||||
olddir = None
|
||||
if chdir:
|
||||
olddir = os.getcwd()
|
||||
os.chdir(chdir)
|
||||
log('running command: %s' % cmd)
|
||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
close_fds=True, shell=shell)
|
||||
ret = proc.wait()
|
||||
output = proc.stdout.read()
|
||||
os.chdir(olddir)
|
||||
if olddir:
|
||||
os.chdir(olddir)
|
||||
return ret, output
|
||||
|
||||
def find_net_info():
|
||||
|
|
@ -422,38 +428,50 @@ def get_options():
|
|||
parser = OptionParser(usage=usage)
|
||||
parser.add_option('-i', '--install', action='store_true', help='Install this daemon as a service', default=False)
|
||||
parser.add_option('-u', '--uninstall', action='store_true', help='Uninstall this daemon if it was installed previously as a service', default=False)
|
||||
parser.add_option('-s', '--scmurl', action='append', help='Forcibly specify an scmurl to checkout from', default=[])
|
||||
parser.add_option('-s', '--scmurl', help='Forcibly specify an scmurl to checkout from')
|
||||
(options, args) = parser.parse_args()
|
||||
return options
|
||||
|
||||
def run_build(workdir, scmurls):
|
||||
def apply_patches(src_dir, patch_dir):
|
||||
patches = [patch for patch in os.listdir(patch_dir) if \
|
||||
os.path.isfile(os.path.join(patch_dir, patch)) and \
|
||||
not patch.startswith('.')]
|
||||
if not patches:
|
||||
raise BuildError, 'no patches found at %s' % patch_dir
|
||||
patches.sort()
|
||||
for patch in patches:
|
||||
cmd = ['/usr/bin/patch', '--verbose', '-d', src_dir, '-p1', '-i', os.path.join(patch_dir, patch)]
|
||||
ret, output = run(cmd)
|
||||
if ret:
|
||||
raise BuildError, 'error applying patches, output was: %s' % output
|
||||
|
||||
def run_build(workdir, source_url, task_opts):
|
||||
"""run the build"""
|
||||
if len(scmurls) == 2:
|
||||
# should SCM.assert_allowed() be called on SCM objs?
|
||||
specurl, srcurl = scmurls
|
||||
spec_scm = SCM(specurl)
|
||||
spec_dir = spec_scm.checkout(workdir)
|
||||
src_scm = SCM(srcurl)
|
||||
src_dir = src_scm.checkout(workdir)
|
||||
elif len(scmurls) == 1:
|
||||
specurl = scmurls[0]
|
||||
spec_scm = SCM(specurl)
|
||||
spec_dir = spec_scm.checkout(workdir)
|
||||
src_scm, src_dir = spec_scm, spec_dir
|
||||
src_scm = SCM(source_url)
|
||||
src_dir = src_scm.checkout(os.path.join(workdir, 'source'))
|
||||
if 'specfile' in task_opts:
|
||||
spec_scm = SCM(task_opts['specfile'])
|
||||
spec_dir = spec_scm.checkout(os.path.join(workdir, 'spec'))
|
||||
else:
|
||||
raise BuildError, 'Unexpected number of SCM URLs given: %s' % scmurls
|
||||
spec_dir = src_dir
|
||||
if 'patches' in task_opts:
|
||||
patch_scm = SCM(task_opts['patches'])
|
||||
patch_dir = patch_scm.checkout(os.path.join(workdir, 'patches'))
|
||||
apply_patches(src_dir, patch_dir)
|
||||
|
||||
specfile = [spec for spec in os.listdir(spec_dir) if spec.endswith('.ini')]
|
||||
if len(specfile) != 1:
|
||||
raise BuildError, 'Exactly one .ini file must be found in a check out'
|
||||
if len(specfile) == 0:
|
||||
raise BuildError, 'No .ini file found'
|
||||
elif len(specfile) > 1:
|
||||
raise BuildError, 'Multiple .ini files found'
|
||||
winbld = WindowsBuild(os.path.join(spec_dir, specfile[0]), src_dir)
|
||||
return winbld.doAll(), src_dir
|
||||
|
||||
def flunk(server_report, server=None):
|
||||
def flunk(server):
|
||||
"""do the right thing when a build fails"""
|
||||
exc_info = sys.exc_info()
|
||||
tb = ''.join(traceback.format_exception(*exc_info))
|
||||
if server_report:
|
||||
if server is not None:
|
||||
server.failTask(tb)
|
||||
log(tb)
|
||||
sys.exit(1)
|
||||
|
|
@ -481,20 +499,27 @@ if __name__ == '__main__':
|
|||
else:
|
||||
print 'Successfully removed the %s service' % prog
|
||||
sys.exit(0)
|
||||
use_server, server = False, None
|
||||
server = None
|
||||
try:
|
||||
if len(opts.scmurl) == 0:
|
||||
use_server = True
|
||||
source_url = None
|
||||
task_opts = None
|
||||
if opts.scmurl:
|
||||
source_url = opts.scmurl
|
||||
else:
|
||||
server = get_mgmt_server()
|
||||
scmurl = server.getTaskInfo()
|
||||
opts.scmurl.append(scmurl)
|
||||
info = server.getTaskInfo()
|
||||
source_url = info[0]
|
||||
if len(info) > 1:
|
||||
task_opts = info[1]
|
||||
if not task_opts:
|
||||
task_opts = {}
|
||||
workdir = '/tmp/workdir'
|
||||
os.mkdir(workdir)
|
||||
results, results_dir = run_build(workdir, opts.scmurl)
|
||||
if use_server:
|
||||
results, results_dir = run_build(workdir, source_url, task_opts)
|
||||
if server is not None:
|
||||
upload_results(server, results_dir, results)
|
||||
server.closeTask(results)
|
||||
log('Build results: %s' % results)
|
||||
except:
|
||||
flunk(use_server, server=server)
|
||||
flunk(server)
|
||||
sys.exit(0)
|
||||
|
|
|
|||
14
vm/kojivmd
14
vm/kojivmd
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
import koji
|
||||
import koji.util
|
||||
from koji.daemon import TaskManager
|
||||
from koji.daemon import SCM, TaskManager
|
||||
from koji.tasks import ServerExit, BaseTaskHandler
|
||||
import sys
|
||||
import logging
|
||||
|
|
@ -125,6 +125,7 @@ def get_options():
|
|||
'max_retries': 120,
|
||||
'offline_retry': True,
|
||||
'offline_retry_interval': 120,
|
||||
'allowed_scms': '',
|
||||
'cert': '/etc/kojivmd/client.crt',
|
||||
'ca': '/etc/kojivmd/clientca.crt',
|
||||
'serverca': '/etc/kojivmd/serverca.crt'}
|
||||
|
|
@ -426,7 +427,7 @@ class VMTask(BaseTaskHandler):
|
|||
thr.setDaemon(True)
|
||||
thr.start()
|
||||
|
||||
def handler(self, name, task_info, opts=None):
|
||||
def handler(self, name, source_url, opts=None):
|
||||
"""
|
||||
Clone the VM named "name", and provide the data in "task_info" to it.
|
||||
Available options:
|
||||
|
|
@ -437,7 +438,14 @@ class VMTask(BaseTaskHandler):
|
|||
opts = {}
|
||||
timeout = opts.get('timeout', 720)
|
||||
|
||||
self.task_info = task_info
|
||||
self.task_info = [source_url, koji.util.dslice(opts, ['specfile', 'patches'],
|
||||
strict=False)]
|
||||
# opts may contain specfile and patches entries, both of which are
|
||||
# urls.
|
||||
# Verify the urls before passing them to the VM.
|
||||
for url in [source_url] + self.task_info[1].values():
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed(self.options.allowed_scms)
|
||||
|
||||
conn = libvirt.open(None)
|
||||
clone_name = self.clone(conn, name)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,13 @@
|
|||
; The URL for the xmlrpc server
|
||||
server=http://hub.example.com/kojihub
|
||||
|
||||
; A space-separated list of hostname:repository[:use_common] tuples that kojivmd is authorized to checkout from (no quotes).
|
||||
; Wildcards (as supported by fnmatch) are allowed.
|
||||
; If use_common is specified and is one of "false", "no", "off", or "0" (without quotes), then kojid will not attempt to checkout
|
||||
; a common/ dir when checking out sources from the source control system. Otherwise, it will attempt to checkout a common/
|
||||
; dir, and will raise an exception if it cannot.
|
||||
allowed_scms=scm.example.com:/cvs/example git.example.org:/example svn.example.org:/users/*:no
|
||||
|
||||
; The mail host to use for sending email notifications
|
||||
smtphost=example.com
|
||||
|
||||
|
|
|
|||
|
|
@ -15,14 +15,16 @@ parser.add_option('--cpus', help='Number of virtual CPUs to allocate to the VM (
|
|||
parser.add_option('--mem', help='Amount of memory (in megabytes) to allocate to the VM (optional)',
|
||||
type='int')
|
||||
parser.add_option('--channel', help='Channel to create the task in', default='vm')
|
||||
parser.add_option('--specfile', help='Alternate SCM URL of the specfile')
|
||||
parser.add_option('--patches', help='SCM URL of patches to apply before build')
|
||||
|
||||
opts, args = parser.parse_args()
|
||||
|
||||
if len(args) < 2:
|
||||
parser.error('You must specify a VM name and a command to run')
|
||||
parser.error('You must specify a VM name and SCM URL')
|
||||
|
||||
vm_name = args[0]
|
||||
cmd = ' '.join(args[1:])
|
||||
scm_url = args[1]
|
||||
|
||||
session = koji.ClientSession(opts.server)
|
||||
session.ssl_login(opts.cert, opts.ca, opts.server_ca)
|
||||
|
|
@ -32,8 +34,12 @@ if opts.cpus:
|
|||
task_opts['cpus'] = opts.cpus
|
||||
if opts.mem:
|
||||
task_opts['mem'] = opts.mem
|
||||
if opts.specfile:
|
||||
task_opts['specfile'] = opts.specfile
|
||||
if opts.patches:
|
||||
task_opts['patches'] = opts.patches
|
||||
|
||||
params = [vm_name, [cmd], task_opts]
|
||||
params = [vm_name, scm_url, task_opts]
|
||||
|
||||
task_id = session.makeTask('vmExec', params, channel=opts.channel)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue