koji version 1.10.1

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJWMlJ6AAoJEI4ybUZMjacl2EwQANP3tcwNcnXQwAYV3I/a0O2g
 4kuwSNRNxD2jhToqIkNJp7LoEsiUFDMHPFl0yxoDmu750wGAnUjCW2P+GlG1fOr/
 Eh65hA9xEn8g8iWPJJSFip2Xz1sLQxrm/zKzV7xaBqiLc6sjZ/dIPfa/LWZjY/e9
 yBnb+I3Wm/RU5QnENMrs1BU0tlZ613Npz9YqalZ4oxPLS4/XzbAJpFkeVLpj9IgM
 EpSEnoNWCMsoIeTN2Uh8YIpU6BzO5fiqPqYq5NqgZMulMPUkzk9xyJFzw5+GtkfF
 DGt5tIy+7J6t86G6VPtKOW+NIfohyJKxyQlz8Mcg8wYrIFiXAM6f6hw0hILhJ8nB
 62McpzlsjvxE2lOLAlW+G2xaEQ272ew01gkx/vNTp0xHAZuHMSveyzTozDIbzcdg
 7ENa8qbY4HGS7qL/Q/J7kHwKPofhKEHXPh2fVRmj/ogzIBM6em87OH3wtHWsz883
 ay6BA9ngBNmBsSU/OBhXDM62BEhjV6oQTxYM1i0ZR2XeUNdJNI7ezHkroMivIEsn
 LafAslR0IpAUtaM8nHVUVLkMBGvUUxm30OTpRiENnkGrV4PnijCty5NLrogIoAtA
 kAf1HH69ls3Xs8rjZS0XXPdim2Vf7EgXvELWwA4AskD8JnA+wmXBfZML6Zhu1k0h
 FQd47eo4SjVNHRpNSUBG
 =Kbwm
 -----END PGP SIGNATURE-----

Merge tag 'koji-1.10.1' into cgen

koji version 1.10.1

Conflicts:
	hub/kojihub.py
This commit is contained in:
Mike McLean 2015-11-02 10:14:21 -05:00
commit ea491f5f03
3 changed files with 197 additions and 21 deletions

153
docs/Writing_a_plugin.md Normal file
View file

@ -0,0 +1,153 @@
# Writing Koji plugins
Depending on what you are trying to do, there are different ways to write a
Koji plugin.
Each is described in this file, by use case.
## Adding new task types
Koji can do several things, for example build RPMs, or live CDs. Those are
types of tasks which Koji knows about.
If you need to do something which Koji does not know yet how to do, you could
create a Koji Builder plugin.
Such a plugin would minimally look like this:
from koji.tasks import BaseTaskHandler
class MyTask(BaseTaskHandler):
Methods = ['mytask']
_taskWeight = 2.0
def handler(self, arg1, arg2, kwarg1=None):
self.logger.debug("Running my task...")
# Here is where you actually do something
A few explanations on what goes on here:
* Your task needs to inherit from `koji.tasks.BaseTaskHandler`
* Your task must have a `Methods` attribute, which is a list of the method
names your task can handle.
* You can specify the weight of your task with the `_taskWeight` attribute.
The more intensive (CPU, IO, ...) your task is, the higher this number
should be.
* The task object has a `logger` attribute, which is a Python logger with the
usual `debug`, `info`, `warning` and `error` methods. The messages you send
with it will end up in the Koji Builder logs (`kojid.log`)
* Your task must have a `handler()` method. That is the method Koji will call
to run your task. It is the method that should actually do what you need. It
can have as many positional and named arguments as you want.
Save your plugin as e.g `mytask.py`, then install it in the Koji Builder
plugins folder: `/usr/lib/koji-builder-plugins/`
Finally, edit the Koji Builder config file, `/etc/kojid/kojid.conf`:
# A space-separated list of plugins to enable
plugins = mytask
Restart the Koji Builder service, and your plugin will be enabled.
You can try running a task from your new task type with the command-line:
$ koji make-task mytask arg1 arg2 kwarg1
## Exporting new API methods over XMLRPC
Koji clients talk to the Koji Hub via an XMLRPC API.
It is sometimes desirable to add to that API, so that clients can request
things Koji does not expose right now.
Such a plugin would minimally look like this:
def mymethod(arg1, arg2, kwarg1=None):
# Here is where you actually do something
mymethod.exported = True
A few explanations on what goes on here:
* Your plugin is just a method, with whatever positional and/or named
arguments you need.
* You must export your method by setting its `exported` attribute to `True`
* The `context.session.assertPerm()` is how you ensure that the
Save your plugin as e.g `mymethod.py`, then install it in the Koji Hub plugins
folder: `/usr/lib/koji-hub-plugins/`
Finally, edit the Koji Hub config file, `/etc/koji-hub/hub.conf`:
# A space-separated list of plugins to enable
Plugins = mymethod
Restart the Koji Hub service, and your plugin will be enabled.
You can try calling the new XMLRPC API with the Python client library:
>>> import koji
>>> session = koji.ClientSession("http://koji/example.org/kojihub")
>>> session.mymethod(arg1, arg2, kwarg1='some value')
### Ensuring the user has the required permissions
If you want your new XMLRPC API to require specific permissions from the user,
all you need to do is add the following to your method:
from koji.context import context
def mymethod(arg1, arg2, kwarg1=None):
context.session.assertPerm("admin")
# Here is where you actually do something
mymethod.exported = True
In the example above, Koji will ensure that the user is an administrator. You
could of course create your own permission, and check for that.
## Running code automatically triggered on events
You might want to run something automatically when something else happens in
Koji.
A typical example is to automatically sign a package right after a build
finished. Another would be to send a notification to a message bus after any
kind of event.
This can be achieved with a plugin, which would look minimally as follows:
from koji.plugin import callback
@callback('preTag', 'postTag')
def mycallback(cbtype, tag, build, user, force=False):
# Here is where you actually do something
A few explanations on what goes on here:
* The `@callback` decorator allows you to declare which events should trigger
your function. You can pass as many as you want. For a list of supported
events, see `koji/plugins.py`.
* The arguments of the function depend on the event you subscribed to. As a
result, you need to know how it will be called by Koji. You probably should
use `*kwargs` to be safe. You can see how callbacks are called in the
`hub/kojihub.py` file, search for calls of the `run_callbacks` function.
Save your plugin as e.g `mycallback.py`, then install it in the Koji Hub
plugins folder: `/usr/lib/koji-hub-plugins`
Finally, edit the Koji Hub config file, `/etc/koji-hub/hub.conf`:
# A space-separated list of plugins to enable
Plugins = mycallback
Restart the Koji Hub service, and your plugin will be enabled.
You can try triggering your callback plugin with the command-line. For
example, if you registered a callback for the `postTag` event, try tagging a
build:
$ koji tag-build mytag mypkg-1.0-1

View file

@ -10387,33 +10387,42 @@ class Host(object):
raise koji.AuthError, "This method requires an exclusive session"
return True
def taskUnwait(self,parent):
def taskUnwait(self, parent):
"""Clear wait data for task"""
c = context.cnx.cursor()
#unwait the task
q = """UPDATE task SET waiting='false' WHERE id = %(parent)s"""
context.commit_pending = True
c.execute(q,locals())
update = UpdateProcessor('task', clauses=['id=%(parent)s'], values=locals())
update.set(waiting=False)
update.execute()
#...and un-await its subtasks
q = """UPDATE task SET awaited='false' WHERE parent=%(parent)s"""
c.execute(q,locals())
update = UpdateProcessor('task', clauses=['parent=%(parent)s'], values=locals())
update.set(awaited=False)
update.execute()
def taskSetWait(self,parent,tasks):
def taskSetWait(self, parent, tasks):
"""Mark task waiting and subtasks awaited"""
self.taskUnwait(parent)
c = context.cnx.cursor()
#mark tasks awaited
q = """UPDATE task SET waiting='true' WHERE id=%(parent)s"""
context.commit_pending = True
c.execute(q,locals())
# mark parent as waiting
update = UpdateProcessor('task', clauses=['id=%(parent)s'], values=locals())
update.set(waiting=True)
update.execute()
# mark children awaited
if tasks is None:
#wait on all subtasks
q = """UPDATE task SET awaited='true' WHERE parent=%(parent)s"""
c.execute(q,locals())
# wait on all subtasks
update = UpdateProcessor('task', clauses=['parent=%(parent)s'], values=locals())
update.set(awaited=True)
update.execute()
else:
for id in tasks:
q = """UPDATE task SET awaited='true' WHERE id=%(id)s"""
c.execute(q,locals())
# wait on specified subtasks
update = UpdateProcessor('task', clauses=['id IN %(tasks)s', 'parent=%(parent)s'], values=locals())
update.set(awaited=True)
update.execute()
# clear awaited flag on any other child tasks
update = UpdateProcessor('task', values=locals(),
clauses=['id NOT IN %(tasks)s', 'parent=%(parent)s', 'awaited=true'])
update.set(awaited=False)
update.execute()
def taskWaitCheck(self,parent):
"""Return status of awaited subtask

View file

@ -15,7 +15,7 @@
%define release %{baserelease}
%endif
Name: koji
Version: 1.10.0
Version: 1.10.1
Release: %{release}%{?dist}
License: LGPLv2 and GPLv2+
# koji.ssl libs (from plague) are GPLv2+
@ -320,6 +320,20 @@ fi
%endif
%changelog
* Thu Oct 29 2015 Mike McLean <mikem at redhat.com> - 1.10.1-1
- fixes for SSL errors
- add support for Image Factory generation of VMWare Fusion Vagrant boxes
- cli: add download-task command
- docs: Document how to write a plugin
- fix for a rare deadlock issue in taskSetWait
- use encode_int on rpm sizes
- check for tag existence in add-pkg
- Remove koji._forceAscii (unused)
- Resolve the canonical hostname when constructing the Kerberos server principal
- don't omit debuginfos on buildinfo page
- correct error message in fastUpload
- Check task method before trying to determine "scratch" status.
* Tue Jul 14 2015 Mike McLean <mikem at redhat.com> - 1.10.0-1
- 1.10.0 release