Really nice to see this documented. +1 ack
On Fri, Jul 10, 2015 at 5:36 PM, Adam Miller <[email protected]> wrote: > On Fri, Jul 10, 2015 at 5:33 PM, Mathieu Bridon <[email protected]> > wrote: > > --- > > > > Koji supports different types of plugins. > > > > This commit documents the 3 types that I know of, but I have absolutely > > no idea if there are others. > > > > docs/Writing_a_plugin.md | 153 > +++++++++++++++++++++++++++++++++++++++++++++++ > > 1 file changed, 153 insertions(+) > > create mode 100644 docs/Writing_a_plugin.md > > > > diff --git a/docs/Writing_a_plugin.md b/docs/Writing_a_plugin.md > > new file mode 100644 > > index 0000000..36cddd9 > > --- /dev/null > > +++ b/docs/Writing_a_plugin.md > > @@ -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 > > -- > > 2.4.3 > > > > Can I +1 more than once? ;) > > But no, seriously this is amazing. Thank you so much for writing this. > > For whatever it's worth: +1 > > -AdamM > > > -- > > buildsys mailing list > > [email protected] > > https://admin.fedoraproject.org/mailman/listinfo/buildsys > -- > buildsys mailing list > [email protected] > https://admin.fedoraproject.org/mailman/listinfo/buildsys > -- -Jon Disnard
-- buildsys mailing list [email protected] https://admin.fedoraproject.org/mailman/listinfo/buildsys
