#!/usr/bin/python -tt
# 
# $Id: libvserver.py 2823 2008-11-06 02:18:50Z dhozac $
# Copyright (C) 2008 Daniel Hokka Zakrisson
# vim:set ts=4 sw=4 expandtab:
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

import _libvserver

class struct:
    _default_ = 0
    def __init__(self, *args, **kwargs):
        l = len(args)
        if l > len(self._fields_):
            raise KeyError, "%s has only %d fields" % (self.__class__,
                                                       len(self._fields_))
        for i in range(0, l):
            self.__dict__[self._fields_[i]] = args[i]
        for i in kwargs.iterkeys():
            if i not in self._fields_:
                raise KeyError, "%s has no such field '%s'" % (self.__class__,
                                                               i)
            self.__dict__[i] = kwargs[i]
    def __totuple(self):
        return tuple(self.__dict__.get(f, self._default_) for f in self._fields_)
    def __iter__(self):
        return self.__totuple().__iter__()
    def __repr__(self):
        return repr(self.__dict__)
    def __addsub(self, other, negator):
        import copy
        c = copy.deepcopy(self)
        for i in vars(other):
            if i in self._fields_:
                c.__dict__[i] = (self.__dict__.get(i, self._default_) +
                                 (negator * getattr(other, i)))
        return c
    def __add__(self, other):
        return self.__addsub(other, 1)
    def __sub__(self, other):
        return self.__addsub(other, -1)

get_vci = _libvserver.vc_get_vci

class struct_ctx_flags(struct):
    _fields_ = ["flagword", "mask"]

def ctx_create(xid, flags=None):
    if flags is None:
        flags = (0, 0)
    elif not isinstance(flags, struct_ctx_flags):
        raise TypeError, "flags must be of type struct_ctx_flags"
    return _libvserver.vc_ctx_create(xid, *flags)
def ctx_migrate(xid, flags=0L):
    return _libvserver.vc_ctx_migrate(xid, flags)

class struct_ctx_stat(struct):
    _fields_ = ["usecnt", "tasks"]
def ctx_stat(xid):
    return struct_ctx_stat(*_libvserver.vc_ctx_stat(xid))

class struct_virt_stat(struct):
    _fields_ = ["offset", "uptime", "nr_threads", "nr_running",
                "nr_uninterruptible", "nr_onhold", "nr_forks",
                "load0", "load1", "load2"]
def virt_stat(xid):
    return struct_virt_stat(*_libvserver.vc_virt_stat(xid))

ctx_kill = _libvserver.vc_ctx_kill
def get_cflags(xid):
    return struct_ctx_flags(*_libvserver.vc_get_cflags(xid))
def set_cflags(xid, flags):
    if not isinstance(flags, struct_ctx_flags):
        raise TypeError, "flags must be of type struct_ctx_flags"
    _libvserver.vc_set_cflags(xid, *flags)

class struct_ctx_caps(struct):
    _fields_ = ["bcaps", "bmask", "ccaps", "cmask"]
def get_ccaps(xid):
    return struct_ctx_caps(*_libvserver.vc_get_ccaps(xid))
def set_ccaps(xid, caps):
    if not isinstance(caps, struct_ctx_caps):
        raise TypeError, "caps must be of type struct_ctx_caps"
    _libvserver.vc_set_ccaps(xid, *caps)

class struct_vx_info(struct):
    _fields_ = ["xid", "initpid"]
def get_vx_info(xid):
    return struct_vx_info(*_libvserver.vc_get_vx_info(xid))

get_task_xid = _libvserver.vc_get_task_xid
wait_exit = _libvserver.vc_wait_exit

class struct_rlimit_mask(struct):
    _fields_ = ["min", "soft", "hard"]
def get_rlimit_mask(xid):
    return struct_rlimit_mask(*_libvserver.vc_get_rlimit_mask(xid))

class struct_rlimit(struct):
    _fields_ = ["min", "soft", "hard"]
    _default_ = _libvserver.VC_LIM_KEEP
def get_rlimit(xid, resource):
    return struct_rlimit(*_libvserver.vc_get_rlimit(xid, resource))
def set_rlimit(xid, resource, limit):
    if not isinstance(limit, struct_rlimit):
        raise TypeError, "limit must be of type struct_rlimit"
    _libvserver.vc_set_rlimit(xid, resource, *limit)

class stuct_rlimit_stat(struct):
    _fields_ = ["hits", "value", "minimum", "maximum"]
def rlimit_stat(xid, resource):
    return struct_rlimit_stat(*_libvserver.vc_rlimit_stat(xid, resource))

reset_minmax = _libvserver.vc_reset_minmax

get_task_nid = _libvserver.vc_get_task_nid
net_create = _libvserver.vc_net_create
net_migrate = _libvserver.vc_net_migrate

class struct_net_addr(struct):
    _fields_ = ["vna_type", "vna_flags", "vna_prefix", "vna_parent", "ip1",
                "ip2", "mask"]

def net_add(nid, addr):
    if not isinstance(addr, struct_net_addr):
        raise TypeError, "addr must be of type struct_net_addr"
    _libvserver.vc_net_add(nid, *addr)

def net_remove(nid, addr):
    if not isinstance(addr, struct_net_addr):
        raise TypeError, "addr must be of type struct_net_addr"
    _libvserver.vc_net_remove(nid, *addr)

class struct_net_flags(struct):
    _fields_ = ["flagword", "mask"]
def get_nflags(nid):
    return struct_net_flags(*_libvserver.vc_get_nflags(nid))
def set_nflags(nid, flags):
    if not isinstance(flags, struct_net_flags):
        raise TypeError, "flags must be of type struct_net_flags"
    _libvserver.vc_set_nflags(nid, *flags)

class struct_net_caps(struct):
    _fields_ = ["ncaps", "cmask"]
def get_ncaps(nid):
    return struct_net_caps(*_libvserver.vc_get_ncaps(nid))
def set_ncaps(nid, caps):
    if not isinstance(caps, struct_net_caps):
        raise TypeError, "caps must be of type struct_net_caps"
    _libvserver.vc_set_ncaps(nid, *caps)

def _vc_set_iattr(f, obj, tag, flags, mask):
    if tag is None:
        tag = 0
    else:
        mask |= _libvserver.VC_IATTR_XID
    f(obj, tag, flags, mask)
def set_iattr(filename, tag=None, flags=0, mask=0):
    _vc_set_iattr(_libvserver.vc_set_iattr, filename, tag, flags, mask)
def fset_iattr(fd, tag=None, flags=0, mask=0):
    _vc_set_iattr(_libvserver.vc_fset_iattr, fd, tag, flags, mask)
get_iattr = lambda f: _libvserver.vc_get_iattr(f, -1)
fget_iattr = lambda f: _libvserver.vc_fget_iattr(f, -1)

def vhi_type(type):
    if isinstance(type, int):
        return type
    else:
        return _libvserver.__dict__["vcVHI_" + repr(type)]
def set_vhi_name(xid, type, val):
    _libvserver.vc_set_vhi_name(xid, vhi_type(type), val)
def get_vhi_name(xid, type):
    return _libvserver.vc_get_vhi_name(xid, vhi_type(type))

enter_namespace = _libvserver.vc_enter_namespace
set_namespace = _libvserver.vc_set_namespace
get_space_mask = _libvserver.vc_get_space_mask
get_space_default = _libvserver.vc_get_space_default

def add_dlimit(path, tag, flags=0):
    _libvserver.vc_add_dlimit(path, tag, flags)
def rem_dlimit(path, tag, flags=0):
    _libvserver.vc_rem_dlimit(path, tag, flags)
class struct_ctx_dlimit(struct):
    _fields_ = ["space_used", "space_total", "inodes_used", "inodes_total",
                "reserved"]
    _default_ = _libvserver.VC_CDLIM_KEEP
def set_dlimit(path, tag, limit, flags=0):
    if not isinstance(limit, struct_ctx_dlimit):
        raise TypeError, "limit must be of type struct_ctx_dlimit"
    _libvserver.vc_set_dlimit(path, tag, flags, *limit)
def get_dlimit(path, tag, flags=0):
    return struct_ctx_dlimit(*_libvserver.vc_get_dlimit(path, tag, flags))

get_task_tag = _libvserver.vc_get_task_tag
tag_create = _libvserver.vc_tag_create
tag_migrate = _libvserver.vc_tag_migrate

class struct_set_sched(struct):
    _fields_ = ["set_mask", "fill_rate", "interval", "fill_rate2", "interval2",
                "tokens", "tokens_min", "tokens_max", "priority_bias",
                "cpu_id", "bucket_id"]
    def fill_set_mask(self):
        if "set_mask" not in self.__dict__:
            self.set_mask = 0
        for field in self.__dict__:
            f = field.replace("priority", "prio").upper()
            self.set_mask |= _libvserver.__dict__.get("VC_VXSM_" + f, 0)
def set_sched(xid, sched):
    if not isinstance(sched, struct_set_sched):
        raise TypeError, "sched must be of type struct_set_sched"
    sched.fill_set_mask()
    _libvserver.vc_set_sched(xid, *sched)
def get_sched(xid, cpu_id=0, bucket_id=0):
    return struct_set_sched(*_libvserver.vc_get_sched(xid, cpu_id, bucket_id))

class struct_sched_info(struct):
    _fields_ = ["cpu_id", "bucket_id", "user_msec", "sys_msec", "hold_msec",
                "token_usec", "vavavoom"]
def sched_info(xid, cpu_id=-1, bucket_id=0):
    if cpu_id == -1:
        import os
        ret = struct_sched_info()
        ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
        seen = 0
        # * 2 is to make sure we get all the processors. CPU hot-plug...
        for cpu in range(0, ncpus * 2):
            try:
                ret += struct_sched_info(*_libvserver.vc_sched_info(xid,
                                                                    cpu, 0))
                seen += 1
            except:
                pass
            if seen == ncpus:
                break
        return ret
    else:
        return struct_sched_info(*_libvserver.vc_sched_info(xid, cpu_id,
                                                               bucket_id))

set_mapping = _libvserver.vc_set_mapping
unset_mapping = _libvserver.vc_unset_mapping

get_badness = _libvserver.vc_get_badness
set_badness = _libvserver.vc_set_badness

get_insecurebcaps = _libvserver.vc_get_insecurebcaps
get_insecureccaps = _libvserver.vc_get_insecureccaps

isSupported = _libvserver.vc_isSupported
isSupportedString = _libvserver.vc_isSupportedString

getXIDType = _libvserver.vc_getXIDType

def xidopt2xid(opt, honor_static=True):
    return _libvserver.vc_xidopt2xid(opt, honor_static)
def nidopt2nid(opt, honor_static=True):
    return _libvserver.vc_nidopt2nid(opt, honor_static)
def tagopt2tag(opt, honor_static=True):
    return _libvserver.vc_tagopt2tag(opt, honor_static)

# XXX: bcap, ccap, cflag, nflag, ncap could all use the same code here.
def text2bcap(text):
    ret = _libvserver.vc_text2bcap(text)
    if ret == 0:
        raise ValueError, "%s is not a valid bcap" % text
    return ret
lobcap2text = _libvserver.vc_lobcap2text
def bcap2list(bcaps):
    list = []
    while True:
        bcaps, text = _libvserver.vc_lobcap2text(bcaps)
        if text is None:
            break
        list.append(text)
    return ",".join(list)
def list2bcap(list):
    bcaps, bmask = _libvserver.vc_list2bcap(list)
    return struct_ctx_caps(bcaps=bcaps, bmask=bmask)

def text2ccap(text):
    ret = _libvserver.vc_text2ccap(text)
    if ret == 0:
        raise ValueError, "%s is not a valid ccap" % text
    return ret
loccap2text = _libvserver.vc_loccap2text
def ccap2list(ccaps):
    list = []
    while True:
        ccaps, text = _libvserver.vc_loccap2text(ccaps)
        if text is None:
            break
        list.append(text)
    return ",".join(list)
def list2ccap(list):
    ccaps, cmask = _libvserver.vc_list2ccap(list)
    return struct_ctx_caps(ccaps=ccaps, cmask=cmask)

def text2cflag(text):
    ret = _libvserver.vc_text2cflag(text)
    if ret == 0:
        raise ValueError, "%s is not a valid cflag" % text
    return ret
locflag2text = _libvserver.vc_locflag2text
def cflag2list(cflags):
    list = []
    while True:
        cflags, text = _libvserver.vc_locflag2text(cflags)
        if text is None:
            break
        list.append(text)
    return ",".join(list)
def list2cflag(list):
    return struct_ctx_flags(*_libvserver.vc_list2cflag(list))

def text2nflag(text):
    ret = _libvserver.vc_text2nflag(text)
    if ret == 0:
        raise ValueError, "%s is not a valid nflag" % text
    return ret
lonflag2text = _libvserver.vc_lonflag2text
def nflag2list(nflags):
    list = []
    while True:
        nflags, text = _libvserver.vc_lonflag2text(nflags)
        if text is None:
            break
        list.append(text)
    return ",".join(list)
def list2nflag(list):
    return struct_net_flags(*_libvserver.vc_list2nflag(list))

def text2ncap(text):
    ret = _libvserver.vc_text2ncap(text)
    if ret == 0:
        raise ValueError, "%s is not a valid ncap" % text
    return ret
loncap2text = _libvserver.vc_loncap2text
def ncap2list(ncaps):
    list = []
    while True:
        ncaps, text = _libvserver.vc_loncap2text(ncaps)
        if text is None:
            break
        list.append(text)
    return ",".join(list)
def list2ncap(list):
    return struct_net_caps(*_libvserver.vc_list2ncap(list))

