Notes about the client api ~~~~~~~~~~~~~~~~~~~~~~~~~~ Starting with Ganeti 1.3, the individual commands (gnt-...) do not execute code directly, but instead via a master daemon. The communication between these commands and the daemon will be language agnostic, and we will be providing a python library implementing all operations. TODO: add tags support, add gnt-instance info implementation, document all results from query and all opcode fields Protocol ======== The protocol for communication will consist of passing JSON-encoded messages over a UNIX socket. The protocol will be send message, receive message, send message, ..., etc. Each message (either request or response) will end (after the JSON message) with a ``ETX`` character (ascii decimal 3), which is not a valid character in JSON messages and thus can serve as a message delimiter. Quoting from the http://www.json.org grammar:: char: any unicode character except " or \ or control character There are three request types than can be done: - submit job; a job is a sequence of opcodes that modify the cluster - abort a job; in some circumstances, a job can be aborted; the exact conditions depend on the master daemon implementation and clients should not rely on being able to abort jobs - query objects; this is a generic form of query that works for all object types All requests will be encoded as a JSON object, having three fields: - ``request``: string, one of ``submit``, ``abort``, ``query`` - ``data``: the payload of the request, variable type based on request - ``version``: the protocol version spoken by the client; we are describing here the version 0 The response to any request will be a JSON object, with two fields: - ``success``: either ``true`` or ``false`` denoting whether the request was successful or not - ``result``: the result of the request (depends on request type) if successful, otherwise the error message (describing the failure) The server has no defined upper-limit on the time it will take to respond to a request, so the clients should implement their own timeout handling. Note though that most requests should be answered quickly, if the cluster is in a normal state. Submit ------ The submit ``data`` field will be a JSON object - a (partial) Job description. It will have the following fields: - ``opcode_list``: a list of opcode objects, see below The opcode objects supported will mostly be the ones supported by the internal Ganeti implementation; currently there is no well-defined definition of them (work in progress). Each opcode will be represented in the message list as an object: - ``OP_ID``: an opcode id; this will be equivalent to the ``OP_ID`` class attribute on opcodes (in lib/opcodes.py) - other fields: as needed by the opcode in question Small example, request:: { "opcode_list": [ { "instance_name": "instance1.example.com", "OP_ID": "OP_INSTANCE_SHUTDOWN" } ] } And response:: { "result": "1104", "success": true } The result of the submit request will be if successful, a single JSON value denoting the job ID. While the job ID might be (or look like) an integer, the clients should not depend on this and treat this ID as an opaque identifier. Abort ----- The abort request data will be a single job ID (as returned by submit or query jobs). The result will hold no data (i.e. it will be a JSON ``null`` value), if successful, and will be the error message if it fails. Query ----- The ``data`` argument to the query request is a JSON object containing: - ``object``: the object type to be queried - ``names``: if querying a list of objects, this can restrict the query to a subset of the entire list - ``fields``: the list of informations that we are interested in The valid values for the ``object`` field is: - ``cluster`` - ``node`` - ``instance`` For the ``cluster`` object, the ``names`` parameter is unused and must be null. The result value will be a list of lists: each row in the top-level list will hold the result for a single object, and each row in the per-object results will hold a result field, in the same order as the ``fields`` value. Small example, request:: { "data": { "fields": [ "name", "admin_memory" ], "object": "instance" }, "request": "query" } And response:: { "result": [ [ "instance1.example.com", "128" ], [ "instance2.example.com", "4096" ] ], "success": true }