API documentation

halonctl.modapi module

class halonctl.modapi.DictFormatter

Convenience subclass of Formatter that works with dicts.

The run() method is customized to use a list of dicts, rather than lists. The dict’s keys are generated from the headers, using the new format_key() method.

format_key(header, args)

Takes a header, and returns the key it should map to in the dictionary.

The default implementation simply calls format_item().

class halonctl.modapi.Formatter

Base class for all formatters.

format(data, args)

Takes a blob of data, and transforms it into the desired form.

What exactly this entrails is obviously up to the formatter, but it should return a string one way or another.

Should be overridden in subclasses.

format_item(item, args)

Takes an emitted item, and returns a more output-friendly form.

The default implementation just calls halonctl.util.textualize().

run(data, args)

Calls format() with data prepared by format_item().

Override if you’d like to customize the entire formatting process, such as if you’d prefer to work with another data structure than a two-dimensional list.

class halonctl.modapi.Module

Base class for all modules.

Variables:
  • exitcode (int) – Change the program’s exit code, to signal an error. (default: 0)
  • partial (bool) – Set to True if the results are partial, will cause the program to exit with code 99 unless --ignore-partial is specified on the commandline.
  • submodules (dict) – If this module has any submodules of its own, specify them as { 'name': ModuleInstance() }, and do not reimplement register_arguments() or run().
register_arguments(parser)

Subclass hook for registering commandline arguments.

Every module has its own subparser, and thus does not have to worry about clobbering other modules’ arguments by accident, but should avoid registering arguments that conflict with halonctl’s own arguments.

Example:

def register_arguments(self, parser):
    parser.add_argument('-t', '--test',
        help="Lorem ipsum dolor sit amet")

See Python’s argparse module for more information, particularly the part about subcommands.

The default implementation registers any subcommands present.

Parameters:parser (argparse.ArgumentParser) – The Argument Parser arguments should be registered on
run(nodes, args)

Invoked when halonctl is run with the module’s name as an argument, and should contain the actual command logic.

To output data, the preferred way is to yield a table, one row at a time, with the first row being the header. This will, by default, output an ASCII art table, but will also allow other formatters to correctly process the data:

def run(self, nodes, args):
    # First, yield a header...
    yield (u"Cluster", u"Node", u"Result")
    
    # Make a call on all given nodes; six.iteritems({}) is used over {}.iteritems()
    # to maintain efficiency and compatibility on both Python 2 and 3
    for node, (code, result) in six.iteritems(nodes.service.someCall(arg=123)):
        # Mark the results as partial if a node isn't responding
        if code != 200:
            self.partial = True
        
        # Yield a row with the response
        yield (node.cluster, node, result or None)

Of course, if your command’s purpose isn’t to retrieve data, you should not do this, and instead adhere to the “rule of silence”; use prints, and say nothing unless there’s an error:

def run(self, nodes, args):
    for node, (code, result) in six.iteritems(nodes.service.someCall(arg=123)):
        if code != 200:
            print "Failure on {node}: {result}".format(node=node, result=result)

The default implementation simply delegates to a subcommand.

halonctl.roles module

class halonctl.roles.HTTPStatus(code)

Denotes an HTTP status code.

Note that the human representation is not always the spec-defined name of the status - in some cases, verbose names have been shortened.

class halonctl.roles.Role

A Role allows you to indicate the meaning of an otherwise context-sensitive value, such as a number. This allows intelligent formatting of values whose meaning would otherwise be impossible to discern.

Feel free to implement your own roles, should you find that no built-in role suits your use-case.

To implement your own Role, simply subclass Role, and override the constructor (to take whatever parameters you need), raw() and human().

human()

Returns a formatted, human-readable representation.

Remember to be brief - your output is likely to be a space-constrained ASCII table; try not to break the layout with excessive verbosity.

raw()

Returns the raw, machine-readable value.

This does not have to be the original value passed in, but should be in a form easily processed by a machine. Human-readability is welcome, but not required nor expected.

class halonctl.roles.StatusCode(code)

A generic status code.

A status code’s raw representation is the code itself, the human representation (meaning) is looked up in a dictionary.

Variables:codes (dict) – A dictionary of status codes to their meanings
class halonctl.roles.UTCDate(timestamp, timezone=0)

Format UTC date with optional timezone

A UTC date’s raw representation is the unixtime itself, the human representation is a nicely formated date string (with timezone)

halonctl.models module

class halonctl.models.Node(data=None, name=None, cluster=None, load_wsdl=False)

A single Halon node.

Variables:
  • name (str) – The configured name of the node.
  • cluster (halon.models.NodeList) – The cluster the node belongs to.
  • scheme (str) – The scheme the node should be accessed over, either http or https
  • host (str) – The hostname of the node
  • username (str) – The effective username; the node’s, if any, otherwise the cluster’s
  • password (str) – The effective password; the node’s or keychain’s, if any, otherwise the cluster’s
command(command, *args, **kwargs)

Convenience function that executes a command on the node, and returns a CommandProxy that can be used to iterate the command’s output, or interact with the running process.

Note that args are the command’s arguments (first one is the command name), while kwargs controls how it’s executed, specified by the following flags:

  • size - the viewport size as (cols, rows), defaults to (80,24)
  • cols, rows - individual components of size
load_data(s)

Updates the node’s data from the given configuration string, overwriting any existing data.

load_wsdl()

Loads the cached WSDL file.

This is called automatically the first time a SOAP call is attempted, or you may call it yourself on startup to e.g. create a bunch of clients at once over a bunch of threads.

make_request(name_, *args, **kwargs)

Convenience function that creates a SOAP request context from a function name and a set of parameters.

The first call to this function is blocking, as the node’s WSDL file will be downloaded synchronously.

service

A proxy that can be used to make SOAP calls to the node.

Return type:halon.proxies.NodeSoapProxy
url

The base URL for the node.

class halonctl.models.NodeList

A list of Halon nodes.

It’s a regular list for all intents and purposes, but with the added benefit of keeping track of credentials, and the ability to execute SOAP calls, either synchronously on one node at a time, or asynchronously on all of them at once.

command(command, *args)

Executes a command across all contained nodes.

load_data(data)

Updates the nodelist’s data from the given configuration dictionary, overwriting any existing data.

service

An asynchronous SOAP proxy.

This is the recommended way to target multiple nodes with a call, as it will only take as long as the slowest node takes to respond, rather than taking longer and longer the mode nodes you’re targeting.

Return type:halon.proxies.NodeListSoapProxy

halonctl.proxies module

class halonctl.proxies.CommandProxy(node, cid)

Proxy for a command executing on a remote server.

This abstracts away all the messy commandRun()/commandPoll() logic, letting you treat a remote process as an interactive iterator.

For example, this will print command output as it arrives:

cmd = node.command('mycommand')
for chunk in cmd:
        print(chunk)
all()

Waits for the process to exit, and returns all of its output.

read()

Reads some data from the remote process’ stdout

resize(size=(80, 24))

Resizes the command’s viewport.

signal(sigid)

Sends a signal to the remote process.

The signal can be specified either as a signal number (eg. 15) or a signal name (eg. SIGTERM).

stop()

Terminates the remote process.

write(data)

Writes some data to the remote process’ stdin.

class halonctl.proxies.NodeListSoapProxy(nodelist)

Multi-node SOAP call proxy.

Similar to NodeSoapProxy, this allows you to easily make SOAP calls, but additionally, these calls are made asynchronously to any number of nodes, taking only as long to return as the slowest node takes to answer.

Returns a dictionary of { node: (status, response) }.

Example:

for node, result in six.iteritems(nodes.myCall(param='abc')):
        # result[0] is the response status; 200 = Success
        if result[0] != 200:
                # ... the call failed, handle the error ...
                print("Error: " + status)
                continue
        
        # result[1] is the response data
        print("{node}: {result}".format(node=node, result=result[1]))
class halonctl.proxies.NodeSoapProxy(node)

SOAP call proxy.

This allows you to make SOAP calls as easily as calling a normal Python function.

Returns a tuple of ( status, response ).

Example:

status, response = node.myCall(param='abc')
if status != 200:
        # ... the call failed, handle the error ...
        print("Error: " + status)

print(response)

halonctl.util module

halonctl.util.ask_confirm(prompt, default=True)

Ask the user for confirmation.

This prompts the user to answer either y/yes or n/no, with a default for if they just hit Enter.

The question is presented as “Prompt [Yn]” or “Prompt [yN]”, depending on the default answer, similar to for instance Debian’s apt-get command. It will repeat until a valid answer is given.

Return type:bool
halonctl.util.async_dispatch(tasks)

Dispatches jobs into a thread pool.

This will take a set of jobs as a dictionary in the form:

{ 'key': (callable, args, kwargs) }

And dispatch it into a thread pool, completing the tasks asynchronously, and returning the results. This will take as long as the slowest job.

halonctl.util.from_base64(s)

Decodes a Base64-encoded string.

This exists because base64.b64decode doesn’t take strings in Python 3, and there’s an awful lot of boilerplate with encodings and handling Nones.

halonctl.util.get_date(s, timezone=0)

Returns a timezone-adjusted date as an arrow object.

halonctl.util.group_by(data, key, unique)

Groups a set of data by a key.

Treating the key as unique will result in a structure of {k:v}, rather than {k:[v,...]}.

Parameters:
  • key (str) – The key to sort by
  • unique (bool) – If the key should be treated as unique
halonctl.util.hql_from_filters(filters, timezone=0)

Gets a HQL statement from a list of filter components.

Filter components may include {YYYY-MM-DD HH:MM:SS} placeholders, which are interpreted according to the given timezone and replaced with UTC timestamps.

Parameters:
  • filters (list) – A list of filters to glue together
  • timezone (int) – The UTC offset of the assumed timezone
halonctl.util.nodesort(nodes)

Sorts a list or dictionary of nodes, by cluster and name.

halonctl.util.open_fuzzy(name, *args, **kwargs)

Opens a file, expanding tildes and creating intermediary directories.

halonctl.util.textualize(item, raw=False)

Performs output conversion of the given item.

It currently has converters for:

Parameters:raw (bool) – Be explicit and machine-readable over human-readable
halonctl.util.to_base64(s)

Encodes a unicode string as Base64.

This exists because base64.b64decode doesn’t take strings in Python 3, and there’s an awful lot of boilerplate with encodings and handling Nones.

halonctl.debug module

halonctl.debug.profile(*args, **kwds)

Profiles a chunk of code, use with the with statement:

from halonctl.debug import profile

with profile('~/Desktop/stats'):
    pass # Do something performance-critical here...

Results for individual runs are collected into to. The specifics of how reports are done varies depending on what type to is.

  • File-like objects: Stats are dumped, according to sort_by, into the stream, separated by newlines - watch out, the file/buffer may grow very big when used in loops.
  • List-like objects: A number of pstats.Stats objects are appended.
  • str and unicode: Treated as a path and opened for appending. Tildes (~) will be expanded, and intermediary directories created if possible.
  • None or omitted: Results are printed to sys.stderr.