channel policy to determine which channel a task is placed in

This commit is contained in:
Mike McLean 2010-05-26 11:23:54 -04:00
parent 6c3bceb313
commit 159ba82013
4 changed files with 95 additions and 17 deletions

View file

@ -475,23 +475,64 @@ def make_task(method,arglist,**opts):
raise koji.GenericError, "Parent task (id %(parent)s) is not open" % opts
#default to a higher priority than parent
opts.setdefault('priority', pdata['priority'] - 1)
for f in ('owner','channel_id','arch'):
for f in ('owner', 'arch'):
opts.setdefault(f,pdata[f])
opts.setdefault('label',None)
else:
opts.setdefault('priority',koji.PRIO_DEFAULT)
#calling function should enforce priority limitations, if applicable
opts.setdefault('arch','noarch')
opts.setdefault('channel','default')
#no labels for top-level tasks
#calling function should enforce channel limitations, if applicable
opts['channel_id'] = get_channel_id(opts['channel'],strict=True)
if not context.session.logged_in:
raise koji.GenericError, 'task must have an owner'
else:
opts['owner'] = context.session.user_id
opts['label'] = None
opts['parent'] = None
#determine channel from policy
policy_data = {}
policy_data['method'] = method
for key in 'arch', 'parent', 'label', 'owner':
policy_data[key] = opts[key]
policy_data['user_id'] = opts['owner']
if 'channel' in opts:
policy_data['req_channel'] = opts['channel']
req_channel_id = get_channel_id(opts['channel'], strict=True)
if method == 'build':
# arglist = source, target, [opts]
args = koji.decode_args2(arglist, ('source', 'target', 'opts'))
policy_data['source'] = args['source']
target = get_build_target(args['target'], strict=True)
policy_data['target'] = target['name']
t_opts = args.get('opts', {})
policy_data['scratch'] = t_opts.get('scratch', False)
ruleset = context.policy.get('channel')
result = ruleset.apply(policy_data)
if result is None:
logger.warning('Channel policy returned no result, using default')
opts['channel_id'] = get_channel_id('default', strict=True)
else:
try:
parts = result.split()
if parts[0] == "use":
opts['channel_id'] = get_channel_id(parts[1], strict=True)
elif parts[0] == "parent":
if not opts.get('parent'):
logger.error("Invalid channel policy result (no parent task): %s",
ruleset.last_rule())
raise koji.GenericError, "invalid channel policy"
opts['channel_id'] = pdata['channel_id']
elif parts[0] == "req":
if 'channel' not in opts:
logger.error('Invalid channel policy result (no channel requested): %s',
ruleset.last_rule())
raise koji.GenericError, "invalid channel policy"
opts['channel_id'] = req_channel_id
else:
logger.error("Invalid result from channel policy: %s", ruleset.last_rule())
raise koji.GenericError, "invalid channel policy"
except IndexError:
logger.error("Invalid result from channel policy: %s", ruleset.last_rule())
raise koji.GenericError, "invalid channel policy"
#XXX - temporary workaround
if method in ('buildArch', 'buildSRPMFromSCM') and opts['arch'] == 'noarch':
#not all arches can generate a proper buildroot for all tags
@ -2166,6 +2207,17 @@ def get_build_targets(info=None, event=None, buildTagID=None, destTagID=None, qu
values=locals(), opts=queryOpts)
return query.execute()
def get_build_target(info, event=None, strict=False):
"""Return the build target with the given name or ID.
If there is no matching build target, return None."""
targets = get_build_targets(info=info, event=event)
if len(targets) == 1:
return targets[0]
elif strict:
raise koji.GenericError, 'No matching build target found: %s' % info
else:
return None
def lookup_name(table,info,strict=False,create=False):
"""Find the id and name in the table associated with info.
@ -4779,6 +4831,14 @@ class ImportedTest(koji.policy.BaseSimpleTest):
#otherwise...
return False
class ChildTaskTest(koji.policy.BoolTest):
name = 'is_child_task'
field = 'parent'
class MethodTest(koji.policy.MatchTest):
name = 'method'
field = 'method'
class IsBuildOwnerTest(koji.policy.BaseSimpleTest):
"""Check if user owns the build"""
name = "is_build_owner"
@ -6476,18 +6536,7 @@ class RootExports(object):
editBuildTarget = staticmethod(edit_build_target)
deleteBuildTarget = staticmethod(delete_build_target)
getBuildTargets = staticmethod(get_build_targets)
def getBuildTarget(self, info, event=None, strict=False):
"""Return the build target with the given name or ID.
If there is no matching build target, return None."""
targets = get_build_targets(info=info, event=event)
if len(targets) == 1:
return targets[0]
else:
if strict:
raise koji.GenericError, 'No matching build target found: %s' % info
else:
return None
getBuildTarget = staticmethod(get_build_target)
def taskFinished(self,taskId):
task = Task(taskId)

View file

@ -466,6 +466,11 @@ _default_policies = {
'package_list' : '''
has_perm admin :: allow
all :: deny
''',
'channel' : '''
has req_channel :: req
is_child_task :: parent
all :: use default
'''
}

View file

@ -365,6 +365,15 @@ def decode_args(*args):
args = args[:-1]
return args,opts
def decode_args2(args, names, strict=True):
"An alternate form of decode_args, returns a dictionary"
args, opts = decode_args(*args)
if strict and len(names) < len(args):
raise TypeError, "Expecting at most %i arguments" % len(names)
ret = dict(zip(names, args))
ret.update(opts)
return ret
def encode_int(n):
"""If n is too large for a 32bit signed, convert it to a string"""
if n <= 2147483647:

View file

@ -60,6 +60,21 @@ class NoneTest(FalseTest):
#alias for false
class HasTest(BaseSimpleTest):
"""Test if policy data contains a field"""
name = "has"
def __init__(self, str):
try:
self.field = str.split(None, 1)[1]
except IndexError:
raise koji.GenericError, "Empty python expression in policy"
def run(self, data):
return self.field in data
class BoolTest(BaseSimpleTest):
"""Test a field in the data as a boolean value