This file is to describe what actions are, how to implement them, and
how to install them. 

This is primarily concerned with the client side python code, and
doesnt attempt to delve into much detail of what it takes to implement
them on the up2date server side, or on the web site, or the database.



1. What are actions?

	As far as the client cares, "actions" are just python
method invocation. 

2. How do I get an action?

	On the server side, actions are queued up into an
actions queue. 

	when rhn_check is ran, either by rhnsd, or by hand,
it connections to the RHN servers, logs in, and then checks
it's action queue. 

	If there are actions in the queue, it pops off the
first one. This is done via xml-rpc encapsulated into
the return of another xml-rpc call. ie:

	client does:
		queue.get()

	If there are actions in the queue, this call will return
a string blob that is an encapsulated xml-rpc call. The reason for
this is that xml-rpc represents a well understood method of representing
both the method being called, and it's arguments.

	The code in rhn_check unmarshals the xml-rpc blob (parses
it into a string for methodname, and a series of data structures representing
the arguments). 

	The next step is for the client to invoke the method with the
said paramaters. But first it has to find the method. The getMethod module
implements this in a fashion where methods can be stored in a 
flexible hiearachy. 

	Once the client finds the method, it invokes it, and captures
it's return status. This return status is sent back to the server
via a queue.submit() call, that updates the status of the action 
info in the database.

3. What can an action do?

	Well, pretty much anything you could do with python. There
are a couple of things to keep in mind though. rhncheck runs the
actions synchronously. Ie, the actions run one after another, waiting
until each completes, so you may want to be careful about writing
extremely long running actions. 
	However, the invocaton, and the return status are done
async though. Ie, the client connects, gets the action, ends the
rpc, and then runs the action. It makes another rpc back to
send the exit status.

===============================================

As mentioned earlier, actions are simply python methods to
the up2date client. The methods are implemented in python
modules or classes. The module files themselves will be
installed into the actions/ dir (typically /usr/share/rhn/up2date/actions)

What A Module File Should Look Like

	Modules exporting methods for use as actions look just like
normal python modules, with a few exceptions:

	1. There needs to be a __rhnactions__ list defined at the
top level of the module. The list is a list of strings of names
of methods that are to be exported from the module.

	2. Filenames begining with '_' will not be elligible to
be used as actions. 

	This is to make it easier to write modular code without
	exporting all the files you need. 


How to Use Classes

	You can use classes inside of module files as well. A 
few rules apply.

	1. There needs to be a __rhnactions__ list defined at
the top level of the class. The list is a list of strings of
names of methods that are to be exported from the module. 

	2. The class needs to be able to run it's contructor with
no arguments. Since the client will need to instantiate the object,
if the init for the class requires additional arguments, this will fail.

	3. the method location approach that the client takes replies
on the __getattr__ method working properly. If you override the __getattr__
method, you need to make sure that the new __getattr__ can at least return
the apprroiate method names for the object. 

Return Code

	The proper return for an action is tuple. The
tuple consists of:

a numeric exit code
a string describing what happend
a "data" dictonary containing arbitrary info
   that can be action specifc. 

On sucess cases, the "data" dictionary can
be empty. 

For failure cases, the "data" dictionary
should contain at least the following
fields:

"version"   almost always "0" but versioning is good
"name"	    typically of the format of methodname.errorcondtion.
	    (an example would be for the packges.remove action that
             fails because of unsolved deps "packges.remove.failed_deps")

The rest of the fields are action specific. 

A success example:
	return (0, "Ate Cheese Succesfully", {})

	return (61, "Item that claimed to be cheese was not in fact cheese",
		{'name':'cheese.eat.thats_not_cheese",
		 'version': '0',
		 'foodstuff':'cottage cheese'})

All, the error return codes are documented and
registered in errstatus.txt in rhn/up2date/errstatus.txt.
If you add a new action with new return codes, please
document there.




===================================
Other Details

	If you make a new directory of actions, you also need to include
an empty __init.py__ in each directory. This is neccasary for the imports
to work correctly.

Adrian

$Id$


