Debugging with Python

From Openpanel Documentation Wiki
Jump to: navigation, search
Important note: Some information on this page may be outdated. This note will be removed if the content has been verified to apply to the 1.0 release.

Most of the documentation on this site (and thus, this page) applies to 1.0. By far the most important change is that opencli is now called openpanel-cli.

NOTE: some output in this document has been reformatted to fit reading width; structure was always preserved.

openpanel-cli is a powerful tool, but it is tailored for administrator usage, which means it's not optimised for development debugging.

However, the Python coreclient module is a fine debugging tool. It's also used for unit-testing OpenPanel - covering RPC, opencore, the database manager and many modules in two fell swoops.

Using coreclient is easy. First, we connect and log in:

Python 2.3.4 (#1, May  2 2007, 19:26:00)
[GCC 3.4.6 20060404 (Red Hat 3.4.6-8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> sys.path.append("/var/openpanel/api/python/package")
>>> from OpenPanel import coreclient
>>> c = coreclient.CoreSession()
>>> c.login(user="admin@example.net", password="foobar")
{'header':
 {'errorid': 0,
  'session_id': '288ccfd5-2ddb-4f6b-378c-035a47f6a81d',
  'error': 'Login succeeded'}}
>>>

We now have a valid session with opencore. Let's list some objects:

>>> c.rpc.getrecords(classid="Domain")
{'body': {'data':{'Domain':
 {'$prototype:master$':
    {'childclasses': {'DNSDomain': 1},
     'class': 'Domain',
     'id': '$prototype:master$',
     'metaid': '$prototype:master$',
     'uuid': '4948cb72-d5d9-4688-54a7-5ad764916d68'},
  'qtrlijh.jylvtjg.fake':
    {'childclasses': {'DNSDomain': 1,
                      'Domain:Alias': 1,
                      'Domain:Vhost': 1,
                      'Mail': 1},
     'class': 'Domain',
     'id': 'qtrlijh.jylvtjg.fake',
     'metaid': 'qtrlijh.jylvtjg.fake',
     'ownerid': '7983af52-404d-4fbc-4c9d-887b21aac775',
     'uuid': '641d6073-72bd-43a1-116c-c4f42b3d5cef'},
  'teypwmi.juechzj.fake':
    {'childclasses': {'DNSDomain': 1,
                      'Domain:Alias': 1,
                      'Domain:Vhost': 1,
                      'Mail': 1},
     'class': 'Domain',
     'id': 'teypwmi.juechzj.fake',
     'metaid': 'teypwmi.juechzj.fake',
     'ownerid': '57670354-ee2b-49dd-317e-8da277927926',
     'uuid': '64ca5b55-b1a3-4230-ac80-373d1b23d3be'}},
 'info': {'total': 3}}},
 'header': {'error': 'OK',
            'errorid': 0,
            'session_id': '288ccfd5-2ddb-4f6b-378c-035a47f6a81d'}}

Note the difference between c. calls and c.rpc. calls. c.rpc.* is a generic method calling proxy that knows nothing about any calls, which makes it perfect for debugging. c. gets more user-friendly wrappers of any calls that can appreciate such, like login and createobject. The current set of wrappers in c.:

    def login(self, user=None, password=None):
        if user:
            return self.rpc.bind(classid="User", id=user, data={"id":password})
        else:
            return self.rpc.bind(classid="User")

    def createobject(self, **args):
         return self.rpc.create(**args)["body"]["data"]["objid"]

    def updateobject(self, **args):
         self.rpc.update(**args)

    def deleteobject(self, objectid):
         self.rpc.delete(objectid=objectid)

Simple wrappers like these can make the API even easier to use; but for debugging, there's nothing like playing around with c.rpc.*.

If you are careful, you can chain calls together whichever way you want; but we recommend sticking to temporary variables to inspect every step of the way. Sometimes you have to dig pretty deep in structures to get the piece of data you want - writing a wrapper is often a quick win.

>>> c.rpc.getactorquota(actorid=c.rpc.getrecord(classid="Actor", 
...     metaid="openadmin")["body"]["data"]["object"]["Actor"]["uuid"]
...     )["body"]["data"]["objects"]["Mail"]
{'units': 'Objects', 'usage': 6, 'quota': -1}
</code>

Prettier:

<code>>>> aid=c.rpc.getrecord(classid="Actor",
...   metaid="openadmin")["body"]["data"]["object"]["Actor"]["uuid"]
>>> c.rpc.getactorquota(actorid=aid)["body"]["data"]["objects"]["Mail"]
{'units': 'Objects', 'usage': 6, 'quota': -1}

Another thing that openpanel-cli can't do right now: call methods.

>>> c.rpc.callmethod(method="installupdates",
...  classid="SoftwareUpdate", parentid="", objectid="updates")
{'body': {'data': {'OpenCORE:Result':
 {'message': 'OK', 'code': 0, 'error': ''}}},
 'header':
  {'errorid': 0,
   'session_id': '4fd48777-2f55-4b1e-86f3-1e7e25a8b69a',
   'error': 'OK'}}

Right now RPC documentation is sparse; one big change that is forthcoming is to make sure method names are more consistent between the RPC layer, opencore, module handling and the database manager. Expect extensive RPC documentation in the future; for now, opencore/rpc.cpp plus the Doxyxen-generated opencore documentation is the best we can offer.

Personal tools
Namespaces
Variants
Actions
Documentation
Tools
Toolbox