#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# This file is part of Karesansui Core.
#
# Copyright (C) 2009 HDE, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#

""" 
<comment-ja>
仮想マシン(VM)の状態取得、起動、停止を行う
</comment-ja>
<comment-en>
Get stats of each VM, and start/stop VM.
</comment-en>

@file:   virt.py

@author: Taizo ITO <taizo@karesansui-project.info>

@copyright:    

"""

import sys
#sys.path.insert(1, '/opt/hde/lib/python')
import string
import os, os.path
import time
import tempfile
import re
import libvirt
import libvirtmod
import logging

# define
from libvirt import VIR_DOMAIN_NOSTATE,VIR_DOMAIN_RUNNING,\
     VIR_DOMAIN_BLOCKED,VIR_DOMAIN_PAUSED,VIR_DOMAIN_SHUTDOWN,\
     VIR_DOMAIN_SHUTOFF,VIR_DOMAIN_CRASHED

import karesansui

from karesansui.lib.const import VIRT_LIBVIRT_DATA_DIR, VIRT_XEN_CONFIG_DIR, \
     VIRT_DISK_IMAGE_DIR, VIRT_BOOT_IMAGE_DIR, VIRT_SNAPSHOT_DIR, \
     VIRT_XML_CONFIG_DIR, VIRT_NETWORK_CONFIG_DIR, VIRT_XENDOMAINS_AUTO_DIR, \
     VIRT_XEN_URI_RO, VIRT_XEN_URI_RW, KARESANSUI_GROUP, \
     XEN_VIRTUAL_DISK_PREFIX, VNC_PORT_MIN_NUMBER, PORT_MAX_NUMBER, \
     VIRT_DISK_DIR, DEFAULT_KEYMAP

from karesansui.lib.virt.config import ConfigParam, ConfigGenerator, \
     XMLConfigGenerator, sync_config_generator

from karesansui.lib.virt.config_network import NetworkConfigParam
from karesansui.lib.virt.config_network import NetworkXMLConfigGenerator

from karesansui.lib.utils import get_xml_parse        as XMLParse
from karesansui.lib.utils import get_xml_xpath        as XMLXpath
from karesansui.lib.utils import get_nums_xml_xpath   as XMLXpathNum
from karesansui.lib.utils import uniq_sort            as UniqSort
from karesansui.lib.utils import generate_mac_address as GenMAC
from karesansui.lib.utils import execute_command      as ExecCmd
from karesansui.lib.utils import string_from_uuid     as StrFromUUID
from karesansui.lib.utils import generate_uuid        as GenUUID
from karesansui.lib.utils import next_number          as NextNumber
from karesansui.lib.utils import create_sparse_file   as MakeSparseFile
from karesansui.lib.utils import copy_file            as CopyFile
from karesansui.lib.net.http import wget              as DownloadFile
from karesansui.lib.utils import is_uuid, get_ifconfig_info, r_chgrp, r_chmod, \
  getfilesize_str, get_filesize_MB

from karesansui.lib.file.configfile import ConfigFile


os.environ['LIBVIRT_XM_CONFIG_DIR'] = VIRT_XEN_CONFIG_DIR

class KaresansuiVirtException(karesansui.KaresansuiLibException):
    pass

class KaresansuiVirtConnection:

    def __init__(self,uri=None,readonly=True):
        self.__prep()
        try:
            self.open(uri,readonly)
        except:
            raise KaresansuiVirtException(_("Cannot open '%s'") % uri)

    def __prep(self):
        if not os.path.exists(VIRT_LIBVIRT_DATA_DIR):
          os.makedirs(VIRT_LIBVIRT_DATA_DIR)
        if not os.path.exists(VIRT_XEN_CONFIG_DIR):
          os.makedirs(VIRT_XEN_CONFIG_DIR)
        if not os.path.exists(VIRT_DISK_IMAGE_DIR):
          os.makedirs(VIRT_DISK_IMAGE_DIR)
        if not os.path.exists(VIRT_BOOT_IMAGE_DIR):
          os.makedirs(VIRT_BOOT_IMAGE_DIR)
        if not os.path.exists(VIRT_SNAPSHOT_DIR):
          os.makedirs(VIRT_SNAPSHOT_DIR)
        if not os.path.exists(VIRT_XML_CONFIG_DIR):
          os.makedirs(VIRT_XML_CONFIG_DIR)
        self.logger = logging.getLogger('karesansui.virt')
        if os.getuid() == 0:
            r_chgrp(VIRT_LIBVIRT_DATA_DIR,KARESANSUI_GROUP)
            r_chgrp(VIRT_XEN_CONFIG_DIR,KARESANSUI_GROUP)

    def open(self, uri,readonly=True):
        if uri is None or uri.lower()[0:3] == "xen":
            if not os.access("/proc/xen", os.R_OK):
                raise 'System is not running a Xen kernel'

        if uri == None:
            if readonly == True:
                self.uri = VIRT_XEN_URI_RO
            else:
                self.uri = VIRT_XEN_URI_RW
        else:
            self.uri = uri

        self.logger.debug('uid=%d' % os.getuid())
        self.logger.debug('gid=%d' % os.getgid())
        try:
            """
            if readonly == True:
                self.logger.info('libvirt.openReadOnly - %s' % self.uri)
                self._conn = libvirt.openReadOnly(self.uri)
            else:
                self.logger.info('libvirt.open - %s' % self.uri)
                self._conn = libvirt.open(self.uri)
            """
            self.logger.debug('libvirt.open - %s' % self.uri)
            self._conn = libvirt.open(self.uri)
        except:
            self.logger.error('failed to libvirt open - %s' % self.uri)

        self.logger.debug('succeed to libvirt open - %s' % self.uri)

        self.guest = KaresansuiVirtGuest(self)
        self.network = KaresansuiVirtNetwork(self)
        return self._conn

    def close(self, conn=None):
        if conn == None:
            try:
                conn = self._conn
            except NameError:
                pass
        if conn != None:
            conn.__del__()
            self.logger.debug('succeed to libvirt close - %s' % self.uri)

    def get_virt_type(self):    
        return self._conn.getType()

    def get_version(self):
        hvType = self.get_virt_type()
        ret = libvirtmod.virGetVersion(hvType)
        libVersion = ret[0]
        apiVersion = ret[1]

        libVersion_major = libVersion / 1000000
        libVersion %= 1000000
        libVersion_minor = libVersion / 1000
        libVersion_rel = libVersion % 1000
        #print "Using library: libvir %d.%d.%d" %(libVersion_major, libVersion_minor, libVersion_rel)

        apiVersion_major = apiVersion / 1000000
        apiVersion %= 1000000
        apiVersion_minor = apiVersion / 1000
        apiVersion_rel = apiVersion % 1000
        #print "Using API: %s %d.%d.%d" %(hvType, apiVersion_major, apiVersion_minor, apiVersion_rel)

        return { "libVersion"  : "%d.%d.%d" %(libVersion_major, libVersion_minor, libVersion_rel),
                 "apiVersion"  : "%s %d.%d.%d" %(hvType, apiVersion_major, apiVersion_minor, apiVersion_rel)
               }

    def get_nodeinfo(self):
        info = dict()
        data = self._conn.getInfo()
        info = {
            "model"        : data[0],
            "memory"       : data[1],
            "cpus"         : data[2],
            "mhz"          : data[3],
            "nodes"        : data[4],
            "sockets"      : data[5],
            "cores"        : data[6],
            "threads"      : data[7]
        }
        return info

    def get_mem_info(self):
        """<comment-ja>
        メモリの情報を取得する。
         - guest_alloc_mem: ゲストOSに割り当てているメモリサイズ,
         - host_max_mem: ホストOSのメモリサイズ,
         - host_free_mem: ホストOSの未割り当てメモリサイズ
         - 単位はMB
        @rtype: dict
        </comment-ja>
        <comment-en>
        </comment-en>
        """
        active_guests = self.list_active_guest()
        inactive_guests = self.list_inactive_guest()
        info = self.get_nodeinfo()
        host_max_mem = info['memory']

        guest_alloc_mem = 0
        
        for domname in active_guests + inactive_guests:
            if not domname == "Domain-0":
                virt = self.search_kvg_guests(domname)[0]
                info = virt.get_info()
                guest_alloc_mem += int(info["maxMem"])
                
        guest_alloc_mem /= 1000  # a unit 'MB'

        host_free_mem = host_max_mem - guest_alloc_mem
        if host_free_mem < 0: host_free_mem = 0

        info = {
            'guest_alloc_mem' : guest_alloc_mem,
            'host_max_mem' : host_max_mem,
            'host_free_mem' : host_free_mem,
        }
        return info

    def is_max_vcpus(self, type=None):
        """<comment-ja>
        ゲストに割り当て可能な仮想CPU数の最大値を取得できるか。

        @param type: ハイパーバイザー
        @return: the maximum number of virtual CPUs supported for a
          guest VM of a specific type.
        @rtype: bool
        </comment-ja>
        <comment-en>
        Get the maximum number of vcpu supported for guest.

        @param type: type of hypervisor
        @return: the maximum number of vcpus
        @rtype: bool
        </comment-en>
        """
        if type is None:
            type = self._conn.getType()
        try:
            max = self._conn.getMaxVcpus(type.lower())
            return True
        except libvirt.libvirtError:
            return False

    def get_max_vcpus(self, type=None):
        """<comment-ja>
        ゲストに割り当て可能な仮想CPU数の最大値を取得する

        @param type: ハイパーバイザー
        @return: the maximum number of virtual CPUs supported for a
          guest VM of a specific type.
        @rtype: integer
        </comment-ja>
        <comment-en>
        Get the maximum number of vcpu supported for guest.

        @param type: type of hypervisor
        @return: the maximum number of vcpus
        @rtype: integer
        </comment-en>
        """
        if type is None:
            type = self._conn.getType()
        try:
            max = self._conn.getMaxVcpus(type.lower())
        except libvirt.libvirtError:
            max = 32
        return max

    def get_physical_cpus(self):
        """<comment-ja>
        物理CPU数を取得する

        @return: 物理CPU数
        @rtype: integer
        </comment-ja>
        <comment-en>
        Get the number of phisical CPUs.

        @return: the number of physical CPUs
        @rtype: integer
        </comment-en>
        """
        info = self.get_nodeinfo()
        return info['nodes'] * info['sockets'] * info['cores'] * info['threads']

    """
    Domain-U
    """
    def set_domain_name(self,name=None):
        self.guest.set_domain_name(name)
    def get_domain_name(self):
        return self.guest.get_domain_name()

    def uuid_to_domname(self, uuid):
        try:
            #guest = self._conn.lookupByUUIDString(uuid)
            #return guest.name()
            for guests in self.search_guests():
                if uuid == guests.UUIDString():
                    return guests.name()
        except:
            return ''

    def domname_to_uuid(self, domname):
        try:
            return self.search_guests(domname)[0].UUIDString()
        except:
            return ''


    def list_inactive_guest(self):
        return self._conn.listDefinedDomains()

    def list_active_guest(self):
        names = []
        for id in self._conn.listDomainsID():
            dom = self._conn.lookupByID(id);
            names.append(dom.name())
        return names

    def search_guests(self, name=None):
        guests = []

        if is_uuid(name):
            name = self.uuid_to_domname(name)

        ids = self._conn.listDomainsID()
        for id in ids:
            guests.append(self._conn.lookupByID(id))
        names = self.list_inactive_guest()
        for _name in names:
            guests.append(self._conn.lookupByName(_name))

        if name == None:
            return guests

        for guest in guests:
            if guest.name() == name:
                return [guest]

        #return []
        raise KaresansuiVirtException("guest %s not found" % name)

    def search_kvg_guests(self, name=None):
        """<comment-ja>
        指定されたゲストOSオブジェクトをKaresansuiVirtGuestオブジェクトのlistにして返却する。
        </comment-ja>
        <comment-en>
        TODO: English Comment
        </comment-en>
        """

        if is_uuid(name):
            name = self.uuid_to_domname(name)

        guests = []
        for guest in self.search_guests(name):
            guests.append(
                KaresansuiVirtGuest(conn=self, name=guest.name()))

        return guests

    def list_used_vnc_port(self):
        ports = []
        for guest in self.search_guests(None):
            document = XMLParse(guest.XMLDesc(1))
            vnc_port = XMLXpath(document, '/domain/devices/graphics/@port')
            if vnc_port and int(vnc_port) > 0:
                ports.append(int(vnc_port))

        return UniqSort(ports)

    def list_used_mac_addr(self):
        addrs = []
        for guest in self.search_guests(None):
            document = XMLParse(guest.XMLDesc(1))
            if_num = XMLXpathNum(document,'/domain/devices/interface')
            for n in range(1, if_num + 1):
                mac_addr = XMLXpath(document,'/domain/devices/interface[%i]/mac/@address' % n)
                addrs.append(mac_addr.lower())
        return addrs

    def set_interface_format(self, format=None):

        if format is None:
            format = "b:xenbr0"

        self.interface_format = []
        for _format in format.split(','):
            (type, name) = _format.split(':')
            if type[0] == 'n':
                try:
                    netinfo = self.search_kvn_networks(name)[0].get_info()
                    self.interface_format.append( {"type": "bridge", "name":netinfo['bridge']['name']} )
                except:
                    raise
            else:
                self.interface_format.append( {"type": "bridge", "name":name} )

    def create_guest(self,name=None, ram=256, disk=None, disksize=1024*16, 
                    mac=None, uuid=None, kernel=None, initrd=None, vnc=None, vcpus=None, extra=None, keymap=DEFAULT_KEYMAP):

        param = ConfigParam(name)

        if disk is None:
            disk = VIRT_DISK_IMAGE_DIR + "/"+ name +".img"

        if mac is None:
            mac = GenMAC()

        if uuid is None:
            uuid = StrFromUUID(GenUUID())

        if vcpus is None:
            vcpus = 1

        if vnc is None:
            used_ports = self.list_used_vnc_port()
            vnc = NextNumber(VNC_PORT_MIN_NUMBER,PORT_MAX_NUMBER,used_ports)

#        if os.path.exists(disk):
#            os.unlink(disk)

        if not os.path.exists(disk):
            MakeSparseFile(disk,int(disksize))

        param.set_uuid(uuid)
        param.set_kernel(kernel)
        param.set_initrd(initrd)
        param.set_max_vcpus(vcpus)
        param.set_memory(str(ram) + 'm')
        param.set_vnc_keymap(keymap)
        param.add_disk(disk, XEN_VIRTUAL_DISK_PREFIX + "a")

        for _format in self.interface_format:
            if _format['name'][0:5] == 'xenbr':
                script = "vif-bridge"
            else:
                script = None

            if mac is None:
                mac = GenMAC()
                param.add_interface(mac,"bridge",_format['name'],script)
            else:
                param.add_interface(mac.lower(),"bridge",_format['name'],script)
                mac = None

        param.set_vnc_port(vnc)
        if extra != None:
            param.append_commandline(extra)
        param.set_behavior("on_shutoff","destroy")
        param.set_behavior("on_reboot","destroy")
        param.set_behavior("on_crash","destroy")

        if not os.path.exists(VIRT_BOOT_IMAGE_DIR):
          os.makedirs(VIRT_BOOT_IMAGE_DIR)

        r = re.compile(r"""(?:ftp|http)s?://""")

        (kfd, kfn) = tempfile.mkstemp(prefix="vmlinuz.", dir=VIRT_BOOT_IMAGE_DIR)
        m = r.match(param.get_kernel())
        if m:
          os.close(kfd)
          DownloadFile(param.get_kernel(),kfn)
        else:
          kernel = open(param.get_kernel(),"r")
          os.write(kfd, kernel.read())
          os.close(kfd)
          kernel.close()
        param.set_kernel(kfn)

        (ifd, ifn) = tempfile.mkstemp(prefix="initrd.img.", dir=VIRT_BOOT_IMAGE_DIR)
        m = r.match(param.get_initrd())
        if m:
          os.close(ifd)
          DownloadFile(param.get_initrd(),ifn)
        else:
          initrd = open(param.get_initrd(),"r")
          os.write(ifd, initrd.read())
          os.close(ifd)
          initrd.close()
        param.set_initrd(ifn)

        sync_config_generator(param)

        if self._conn is None:
            self._conn = self.open(None)

        generator = XMLConfigGenerator()
        try:
            cfgxml = generator.generate(param)
        except:
            raise
        dom = self._conn.createLinux(cfgxml, 0)
        time.sleep(1)
        try:
            self._conn.lookupByID(dom.ID())
        except libvirt.libvirtError:
            raise "create_guest() error. name:%s" % (name)

        os.unlink(param.get_initrd())
        os.unlink(param.get_kernel())
        param.set_kernel(None)
        param.set_initrd(None)
        param.cmdline = []
        param.set_bootloader("/usr/bin/pygrub")
        param.set_behavior("on_reboot","restart")
        param.set_behavior("on_crash","restart")

        sync_config_generator(param)

    def start_guest(self,name=None):
        if not (name is None):
            self.guest.set_domain_name(name)
        self.guest.create()

    def shutdown_guest(self,name=None):
        if not (name is None):
            self.guest.set_domain_name(name)
        self.guest.shutdown()

    def reboot_guest(self,name=None):
        if not (name is None):
            self.guest.set_domain_name(name)
        self.guest.reboot()

    def destroy_guest(self,name=None):
        if not (name is None):
            self.guest.set_domain_name(name)
        self.guest.destroy()

    def delete_guest(self,name=None):
        self.destroy_guest(name)

        config = "%s/%s" %(VIRT_XEN_CONFIG_DIR, self.guest.get_domain_name())
        if os.path.exists(config):
            os.unlink(config)
        config = "%s/%s.xml" %(VIRT_XML_CONFIG_DIR, self.guest.get_domain_name())
        if os.path.exists(config):
            os.unlink(config)

        domain_snapshot_dir = "%s/%s" %(VIRT_SNAPSHOT_DIR, self.guest.get_domain_name())
        if os.path.exists(domain_snapshot_dir):
            os.removedirs(domain_snapshot_dir)

        domain_disk_dir = "%s/%s" %(VIRT_DISK_DIR, self.guest.get_domain_name())
        if os.path.exists(domain_disk_dir):
            os.removedirs(domain_disk_dir)

    def suspend_guest(self,name=None):
        if not (name is None):
            self.guest.set_domain_name(name)
        self.guest.suspend()

    def resume_guest(self,name=None):
        if not (name is None):
            self.guest.set_domain_name(name)
        self.guest.resume()

    def take_snapshot(self, name, title=None):
        if not (name is None):
            self.guest.set_domain_name(name)
        self.guest.snapshot(title)

    def apply_snapshot(self,title=None,name=None):
        if not (name is None):
            self.guest.set_domain_name(name)

        domain_snapshot_dir = VIRT_SNAPSHOT_DIR + "/" + self.guest.get_domain_name()
        filename = domain_snapshot_dir + "/" + title
        if os.path.exists(filename):
            try:
                self.guest.restore(filename)
            except:
                return False
        else:
            return False

        return True

    def list_snapshot(self,name=None):
        if not (name is None):
            self.guest.set_domain_name(name)

        domain_snapshot_dir = VIRT_SNAPSHOT_DIR + "/" + self.guest.get_domain_name()
        if os.path.exists(domain_snapshot_dir):
            return os.listdir(domain_snapshot_dir)
        else:
            return None

    def autostart_guest(self,flag=None,name=None):
        if not (name is None):
            self.guest.set_domain_name(name)
        guests = self.search_guests(self.guest.get_domain_name())
        if len(guests):
            return self.guest.autostart(flag)
        else:
            return False

    def replicate_guest(self, name, source_name, mac=None, uuid=None, vnc=None):

        param = ConfigParam(name)

        xml_file = "%s/%s.xml" % (VIRT_XML_CONFIG_DIR, source_name)
        if not os.path.exists(xml_file):
            dom = self._conn.lookupByName(source_name)
            ConfigFile(xml_file).write(dom.XMLDesc(0))
            if os.getuid() == 0 and os.path.exists(xml_file):
                r_chgrp(xml_file,KARESANSUI_GROUP)
        param.load_xml_config(xml_file)

        source_disk = VIRT_DISK_IMAGE_DIR + "/"+ source_name +".img"
        disk = VIRT_DISK_IMAGE_DIR + "/"+ name +".img"

        src_interfaces = param.interfaces
        param.interfaces = []
        for ifs in src_interfaces:
            script = ifs['script']
            if mac is None:
                mac = GenMAC()
                param.add_interface(mac,"bridge",ifs['bridge'],script)
            else:
                param.add_interface(mac.lower(),"bridge",ifs['bridge'],script)
                mac = None

        if uuid is None:
            uuid = StrFromUUID(GenUUID())

        if vnc is None:
            used_ports = self.list_used_vnc_port()
            vnc = NextNumber(VNC_PORT_MIN_NUMBER,PORT_MAX_NUMBER,used_ports)

        param.disks = []
        param.set_uuid(uuid)
        param.set_vnc_port(vnc)
        param.add_disk(disk,XEN_VIRTUAL_DISK_PREFIX + "a")

        try:
            if not os.path.exists(disk):
                CopyFile(source_disk,disk)
        except:
            raise

        sync_config_generator(param, name)

    """
    Network
    """
    def list_inactive_network(self):
        return self._conn.listDefinedNetworks()

    def list_active_network(self):
        names = []
        for name in self._conn.listNetworks():
            names.append(name)
        return names

    def search_networks(self, name=None):
        networks = []

        names = self._conn.listNetworks()
        for __name in names:
            networks.append(self._conn.networkLookupByName(__name))
        names = self.list_inactive_network()
        for __name in names:
            networks.append(self._conn.networkLookupByName(__name))

        if name == None:
            return networks

        regex_regex = re.compile(r"""^regex:(?P<regex>.*)""")
        m = regex_regex.match(name)

        n_networks = []
        for network in networks:
            network_name = network.name()
            if m == None:
                if network_name == name:
                    return [network]
            else:
                regex = m.group('regex')
                query_regex = re.compile(r""+regex+"")
                n = query_regex.search(network_name)
                if n != None:
                    n_networks.append(network)
        if len(n_networks):
            return n_networks

        #return []
        raise KaresansuiVirtException("network %s not found" % name)

    def search_kvn_networks(self, name=None):
        """<comment-ja>
        指定された仮想ネットワークオブジェクトをKaresansuiVirtNetworkオブジェクトのlistにして返却する。
        </comment-ja>
        <comment-en>
        TODO: English Comment
        </comment-en>
        """

        if is_uuid(name):
            name = self.uuid_to_domname(name)

        networks = []
        for network in self.search_networks(name):
            networks.append(
                KaresansuiVirtNetwork(conn=self, name=network.name()))

        return networks

    def create_network(self, name, cidr, dhcp_start=None, dhcp_end=None, forward=None, bridge=None):
        param = NetworkConfigParam(name)
        param.set_default_networks(cidr,dhcp_start,dhcp_end)
        param.set_ipaddr_and_netmask(cidr)
        if forward:
            if 'dev' in forward.keys():
                param.set_forward_dev(forward['dev'])
            if 'mode' in forward.keys():
                param.set_forward_mode(forward['mode'])
        if bridge:
            param.set_bridge(bridge)
        uuid = StrFromUUID(GenUUID())
        param.set_uuid(uuid)

        generator = NetworkXMLConfigGenerator()
        try:
            cfgxml = generator.generate(param)
        except:
            raise
        generator.writecfg(cfgxml)

        ret = libvirtmod.virNetworkCreateXML(self._conn._o,cfgxml)
        return ret

    def update_network(self, name, cidr=None, dhcp_start=None, dhcp_end=None, forward=None, bridge=None):
        # パラメータをリセットする場合と引数が無い場合の区別 => リセットの場合は、空文字列を渡す。

        if not ( cidr or
                 dhcp_start or
                 dhcp_end or
                 forward or
                 bridge ):
            # Not changed, do nothing
            # 更新成功時と同じ返り値(0)を返す
            return 0

        try:
            param  = self.search_kvn_networks(name)[0].get_network_config_param()
        except:
            raise KaresansuiVirtException("Can't get parameters of network '%s'." % name)

        if cidr:
            param.set_ipaddr_and_netmask(cidr)
        if dhcp_start:
            param.set_dhcp_start(dhcp_start)
        if dhcp_end:
            param.set_dhcp_end(dhcp_end)
        if forward:
            if 'dev' in forward.keys():
                if forward['dev'] == '':
                    param.set_forward_dev(None)
                else:
                    param.set_forward_dev(forward['dev'])
            if 'mode' in forward.keys():
                if forward['mode'] == '':
                    param.set_forward_mode(None)
                else:
                    param.set_forward_mode(forward['mode'])
        if bridge:
            param.set_bridge(bridge)

        generator = NetworkXMLConfigGenerator()
        try:
            cfgxml = generator.generate(param)
        except:
            raise

        self.stop_network(name)

        generator.writecfg(cfgxml)

        ret = libvirtmod.virNetworkCreateXML(self._conn._o,cfgxml)
        return ret

    def start_network(self,name=None):
        if not (name is None):
            self.network.set_network_name(name)
        self.network.start()

    def stop_network(self,name=None):
        if not (name is None):
            self.network.set_network_name(name)
        self.network.stop()

    def delete_network(self,name=None):
        self.stop_network(name)
        if len(self.search_networks(name)) > 0:
            self.network.undefine()

        config = "%s/%s.xml" %(VIRT_NETWORK_CONFIG_DIR, self.network.get_network_name())
        if os.path.exists(config):
            os.unlink(config)

        config = "%s/autostart/%s.xml" %(VIRT_NETWORK_CONFIG_DIR, self.network.get_network_name())
        if os.path.exists(config):
            os.unlink(config)

    def autostart_network(self,flag=None,name=None):
        if not (name is None):
            self.guest.set_domain_name(name)
        networks = self.search_networks(self.network.get_network_name())
        if len(networks):
            return self.network.autostart(flag)
        else:
            return False

class KaresansuiVirtGuest:

    def __init__(self, conn, name=None):
        self.connection = conn
        self._conn = self.connection._conn
        self.set_domain_name(name)

    def get_json(self):
        """<comment-ja>
        JSON形式でKaresansuiVirtGuest情報を返却する。
        </comment-ja>
        <comment-en>
        TODO: English Comment
        </comment-en>
        """
        
        ret = {}
        ret['name'] = self.get_domain_name()
        ret.update(self.get_info())
        return ret

    def set_domain_name(self,name=None):
        if is_uuid(name):
            self.domain = conn.uuid_to_domname(name)
        else:
            self.domain = name

    def get_domain_name(self):
        return self.domain

    def get_info(self):
        dom = self._conn.lookupByName(self.get_domain_name())
        data = dom.info()
        try:
            os_type = dom.OSType()
        except:
            os_type = None
        return {
                "state"     : data[0],
                "maxMem"    : data[1],
                "memory"    : data[2],
                "nrVirtCpu" : data[3],
                "cpuTime"   : data[4],
                "OSType"    : os_type,
        }

    def get_netinfo(self):
        info = {}
        dom = self._conn.lookupByName(self.get_domain_name())
        dom_id = dom.ID()
        vif_info = get_ifconfig_info("regex:^vif%d\.[0-9]" % dom_id)
        for dev,value in vif_info.iteritems():
            dev = dev.replace("vif%d." % (dom_id,), "eth")
            info[dev] = value
        return info

    def get_disk_info(self):
        infos = []
        dom = self._conn.lookupByName(self.get_domain_name())

        document = XMLParse(dom.XMLDesc(1))
        disk_num = XMLXpathNum(document,'/domain/devices/disk')
        for n in range(1, disk_num + 1):
            driver = {}
            source = {}
            target = {}
            type   = XMLXpath(document,'/domain/devices/disk[%i]/@type' % n)
            device = XMLXpath(document,'/domain/devices/disk[%i]/@device' % n)
            driver['name'] = XMLXpath(document,'/domain/devices/disk[%i]/driver/@name' % n)
            driver['type'] = XMLXpath(document,'/domain/devices/disk[%i]/driver/@type' % n)
            source['file'] = XMLXpath(document,'/domain/devices/disk[%i]/source/@file' % n)
            target['dev'] = XMLXpath(document,'/domain/devices/disk[%i]/target/@dev' % n)
            target['bus'] = XMLXpath(document,'/domain/devices/disk[%i]/target/@bus' % n)
            if os.path.exists(source['file']):
                source['size'] = get_filesize_MB(getfilesize_str(source['file']))
            else:
                source['size'] = 0
            info = {
                   "type":type,
                   "device":device,
                   "driver":driver,
                   "source":source,
                   "target":target,
                   }
            infos.append(info)
        return infos

    def get_vcpus_info(self):
        dom = self._conn.lookupByName(self.get_domain_name())

        document = XMLParse(dom.XMLDesc(1))
        try:
            max_vcpus = int(XMLXpath(document,'/domain/vcpu/text()'))
        except:
            max_vcpus = None
        try:
            if self.status() != VIR_DOMAIN_SHUTOFF:
                vcpus = self.get_info()['nrVirtCpu']
            else:
                vcpus = None
        except:
            vcpus = None
        try:
            xml_file = "%s/%s.xml" % (VIRT_XML_CONFIG_DIR, self.get_domain_name())
            document = XMLParse(xml_file)
            bootup_vcpus = int(XMLXpath(document,'/domain/vcpu/text()'))
        except:
            bootup_vcpus = None

        return {
                "max_vcpus"    :max_vcpus,
                "vcpus"        :vcpus,
                "bootup_vcpus" :bootup_vcpus,
               }

    def get_interface_info(self):
        infos = []
        dom = self._conn.lookupByName(self.get_domain_name())

        document = XMLParse(dom.XMLDesc(1))
        disk_num = XMLXpathNum(document,'/domain/devices/interface')
        for n in range(1, disk_num + 1):
            mac = {}
            source = {}
            script = {}
            target = {}
            type   = XMLXpath(document,'/domain/devices/interface[%i]/@type' % n)
            mac['address'] = XMLXpath(document,'/domain/devices/interface[%i]/mac/@address' % n)
            source['bridge'] = XMLXpath(document,'/domain/devices/interface[%i]/source/@bridge' % n)
            source['network'] = XMLXpath(document,'/domain/devices/interface[%i]/source/@network' % n)
            source['address'] = XMLXpath(document,'/domain/devices/interface[%i]/source/@address' % n)
            source['port'] = XMLXpath(document,'/domain/devices/interface[%i]/source/@port' % n)
            script['path'] = XMLXpath(document,'/domain/devices/interface[%i]/script/@path' % n)
            target['dev'] = XMLXpath(document,'/domain/devices/interface[%i]/target/@dev' % n)
            info = {
                   "type":type,
                   "mac":mac,
                   "source":source,
                   "script":script,
                   "target":target,
                   }
            infos.append(info)
        return infos

    def get_graphics_info(self):

        """ current info """
        dom = self._conn.lookupByName(self.get_domain_name())
        document = XMLParse(dom.XMLDesc(1))
        type = XMLXpath(document,'/domain/devices/graphics/@type')
        port = XMLXpath(document,'/domain/devices/graphics/@port')
        autoport = XMLXpath(document,'/domain/devices/graphics/@autoport')
        listen = XMLXpath(document,'/domain/devices/graphics/@listen')
        keymap = XMLXpath(document,'/domain/devices/graphics/@keymap')
        current_info = {
                       "type"    :type,
                       "port"    :port,
                       "autoport":autoport,
                       "listen"  :listen,
                       "keymap"  :keymap,
                       }

        """ current setting """
        param = ConfigParam(self.get_domain_name())
        xml_file = "%s/%s.xml" % (VIRT_XML_CONFIG_DIR, self.get_domain_name())
        if not os.path.exists(xml_file):
            dom = self._conn.lookupByName(self.get_domain_name())
            ConfigFile(xml_file).write(dom.XMLDesc(0))
            if os.getuid() == 0 and os.path.exists(xml_file):
                r_chgrp(xml_file,KARESANSUI_GROUP)
        param.load_xml_config(xml_file)
        port     = param.get_vnc_port()
        autoport = param.get_vnc_autoport()
        listen   = param.get_vnc_listen()
        keymap   = param.get_vnc_keymap()
        passwd   = param.get_vnc_passwd()
        current_setting = {
                       "port"    :port,
                       "autoport":autoport,
                       "listen"  :listen,
                       "keymap"  :keymap,
                       "passwd"  :passwd,
                       }

        return {"info":current_info,"setting":current_setting}

    def create(self):
        if self.is_creatable() is True:
            time.sleep(1)
            dom = self._conn.lookupByName(self.get_domain_name())
            dom.create()
            for x in range(0,5):
                time.sleep(1)
                if self.status() != VIR_DOMAIN_SHUTOFF:
                    break

    def shutdown(self):
        if self.is_shutdownable() is True:
            time.sleep(1)
            dom = self._conn.lookupByName(self.get_domain_name())
            dom.shutdown()
            for x in range(0,120):
                time.sleep(1)
                if self.status() == VIR_DOMAIN_SHUTOFF:
                    break

    def reboot(self):
        if self.is_shutdownable() is True:
            time.sleep(1)
            dom = self._conn.lookupByName(self.get_domain_name())

            """
            dom.reboot(0)
            """
            dom.shutdown()
            for x in range(0,480):
                time.sleep(1)
                if self.status() == VIR_DOMAIN_SHUTOFF:
                    break
            dom.create()

            for x in range(0,30):
                time.sleep(1)
                if self.status() != VIR_DOMAIN_SHUTOFF:
                    break

    def destroy(self):
        if self.is_destroyable() is True:
            time.sleep(1)
            dom = self._conn.lookupByName(self.get_domain_name())
            dom.destroy()
            for x in range(0,120):
                time.sleep(1)
                if self.status() == VIR_DOMAIN_SHUTOFF:
                    break

    def suspend(self):
        if self.is_suspendable() is True:
            time.sleep(1)
            dom = self._conn.lookupByName(self.get_domain_name())
            dom.suspend()
            for x in range(0,5):
                time.sleep(1)
                if self.status() == VIR_DOMAIN_PAUSED:
                    break

    def resume(self):
        if self.is_resumable() is True:
            time.sleep(1)
            dom = self._conn.lookupByName(self.get_domain_name())
            dom.resume()
            for x in range(0,5):
                time.sleep(1)
                if self.status() != VIR_DOMAIN_PAUSED:
                    break

    def status(self):
        return self.get_info()["state"]

    def save(self,file):
        dom = self._conn.lookupByName(self.get_domain_name())
        dom.save(file)
        for x in range(0,120):
            time.sleep(1)
            if self.status() == VIR_DOMAIN_SHUTOFF:
                break

    def restore(self,file):

        if not os.path.exists(file):
            raise KaresansuiVirtException("file %s not found" % file)

        if self.status() != VIR_DOMAIN_SHUTOFF:
            self.destroy()

        self._conn.restore(file)
        for x in range(0,60):
            time.sleep(1)
            if self.status() != VIR_DOMAIN_SHUTOFF:
                break

        from karesansui.lib.virt.config import ConfigParam
        param = ConfigParam(self.get_domain_name())

        xml_file = "%s/%s.xml" % (VIRT_XML_CONFIG_DIR, self.get_domain_name())
        if not os.path.exists(xml_file):
            dom = self._conn.lookupByName(self.get_domain_name())
            ConfigFile(xml_file).write(dom.XMLDesc(0))
            if os.getuid() == 0 and os.path.exists(xml_file):
                r_chgrp(xml_file,KARESANSUI_GROUP)
        param.load_xml_config(xml_file)

        param.set_current_snapshot(file)

        sync_config_generator(param, self.get_domain_name())

    def snapshot(self,title=None):

        status = self.status()
        if status == VIR_DOMAIN_PAUSED:
            self.resume()

        if status == VIR_DOMAIN_SHUTOFF:
            raise KaresansuiVirtException("guest %s is stopped." % self.get_domain_name())

        domain_snapshot_dir = VIRT_SNAPSHOT_DIR + "/" + self.get_domain_name()

        if not os.path.exists(VIRT_SNAPSHOT_DIR):
            os.makedirs(VIRT_SNAPSHOT_DIR)

        if not os.path.exists(domain_snapshot_dir):
            os.makedirs(domain_snapshot_dir)

        if title == None:
            title = "%f" % time.time()

        filename = domain_snapshot_dir + "/" + title
        self.save(filename)

        if status != VIR_DOMAIN_SHUTOFF:
            self.restore(filename)

        if status == VIR_DOMAIN_PAUSED:
            self.suspend()

    def autostart(self, flag=None):

        if self._conn.getType() == "Xen":
            autostart_file = "%s/%s" %(VIRT_XENDOMAINS_AUTO_DIR,self.get_domain_name())

            if flag == True:
                if not os.path.exists(autostart_file):
                    command_args = [
                        "/bin/ln", "-s",
                        "%s/%s" %(VIRT_XEN_CONFIG_DIR,self.get_domain_name()),
                        "%s" % VIRT_XENDOMAINS_AUTO_DIR
                    ]
                    ret = ExecCmd(command_args)
            elif flag == False:
                if os.path.exists(autostart_file):
                    os.unlink(autostart_file)
            else:
                return not os.path.exists(autostart_file)

    def next_disk_target(self):

        dom = self._conn.lookupByName(self.get_domain_name())
        serials = []

        document = XMLParse(dom.XMLDesc(1))

        disk_num = XMLXpathNum(document,'/domain/devices/disk')
        prefix = XEN_VIRTUAL_DISK_PREFIX
        for n in range(1, disk_num + 1):
            target_dev = XMLXpath(document,'/domain/devices/disk[%i]/target/@dev' % n)
            p = re.compile(r"""^(?P<prefix>[a-z]+)(?P<serial>[a-z])$""")
            m = p.match(target_dev)
            prefix = m.group("prefix")
            serials.append(m.group("serial"))

        for i,_x in enumerate('abcdefghijklmnopqrstuvwxyz'):
          if not _x in serials:
            next_serial = _x
            break

        return "%s%s" %(prefix, next_serial)

    def add_disk(self, path, target, size, is_sparse=True):

        domain_disk_dir = "%s/%s" % (VIRT_DISK_DIR, self.get_domain_name())
        if os.path.exists(VIRT_DISK_DIR) is False:
            os.makedirs(VIRT_DISK_DIR)
            
        if not os.path.exists(domain_disk_dir):
            os.makedirs(domain_disk_dir)
        
        from karesansui.lib.utils import create_sparse_file
        try:
            create_sparse_file(path, size, is_sparse)
            return self.append_disk(path,target)
        except:
            if os.path.exists(path) is True:
                os.remove(path)
            raise

    def append_disk(self,path,target):

        from karesansui.lib.virt.config import ConfigParam
        param = ConfigParam(self.get_domain_name())
        dom = self._conn.lookupByName(self.get_domain_name())

        xml_file = "%s/%s.xml" % (VIRT_XML_CONFIG_DIR, self.get_domain_name())
        if not os.path.exists(xml_file):
            ConfigFile(xml_file).write(dom.XMLDesc(0))
            if os.getuid() == 0 and os.path.exists(xml_file):
                r_chgrp(xml_file,KARESANSUI_GROUP)
        param.load_xml_config(xml_file)

        param.add_disk(path,target)

        try:
            from karesansui.lib.virt.config import XMLDiskConfigGenerator
            generator = XMLDiskConfigGenerator()
            generator.set_path(path)
            generator.set_target(target)
            cfg = generator.generate(None)
            dom.attachDevice(cfg)
        except:
            raise

        sync_config_generator(param, self.get_domain_name())

    def delete_disk(self,target):
        status = self.status()
        if status == VIR_DOMAIN_PAUSED:
            self.resume()
            time.sleep(2)
            #raise KaresansuiVirtException("Domain %s is suspended." % self.get_domain_name())

        from karesansui.lib.virt.config import ConfigParam
        param = ConfigParam(self.get_domain_name())
        dom = self._conn.lookupByName(self.get_domain_name())

        xml_file = "%s/%s.xml" % (VIRT_XML_CONFIG_DIR, self.get_domain_name())
        if not os.path.exists(xml_file):
            ConfigFile(xml_file).write(dom.XMLDesc(0))
            if os.getuid() == 0 and os.path.exists(xml_file):
                r_chgrp(xml_file,KARESANSUI_GROUP)
        param.load_xml_config(xml_file)

        path = param.get_disk_path(target)

        # physical disk remove
        if path is not None and os.path.exists(path) is True:
            try:
                os.remove(path)
            except:
                self.logger.info("You do not have a disk file. - %s" % path)
                raise
        param.delete_disk(target)

        try:
            from karesansui.lib.virt.config import XMLDiskConfigGenerator
            generator = XMLDiskConfigGenerator()
            generator.set_target(target)
            generator.set_path(path)
            cfg = generator.generate(None)
            """
            try:
                dom.detachDevice(cfg)
            except:
                xml_generator = XMLConfigGenerator()
                cfgxml = xml_generator.generate(param)
                self._conn.defineXML(cfgxml)
            """
            xml_generator = XMLConfigGenerator()
            cfgxml = xml_generator.generate(param)
            self._conn.defineXML(cfgxml)

            if status == VIR_DOMAIN_PAUSED:
                self.suspend()
        except:
            raise

        sync_config_generator(param, self.get_domain_name())

    def append_interface(self,mac,bridge=None,network=None):

        from karesansui.lib.virt.config import ConfigParam
        param = ConfigParam(self.get_domain_name())
        dom = self._conn.lookupByName(self.get_domain_name())

        xml_file = "%s/%s.xml" % (VIRT_XML_CONFIG_DIR, self.get_domain_name())
        if not os.path.exists(xml_file):
            ConfigFile(xml_file).write(dom.XMLDesc(0))
            if os.getuid() == 0 and os.path.exists(xml_file):
                r_chgrp(xml_file,KARESANSUI_GROUP)
        param.load_xml_config(xml_file)

        if network is not None:
            netinfo = self.connection.search_kvn_networks(network)[0].get_info()
            bridge = netinfo['bridge']['name']

        if bridge[0:5] == 'xenbr':
            script = "vif-bridge"
        else:
            script = None
        mac = mac.lower()
        param.add_interface(mac,"bridge",bridge,script)

        try:
            from karesansui.lib.virt.config import XMLInterfaceConfigGenerator
            generator = XMLInterfaceConfigGenerator()
            generator.set_mac(mac)
            generator.set_bridge(bridge)
            if script is not None:
                generator.set_script(script)
            cfg = generator.generate(None)
            dom.attachDevice(cfg)
        except:
            raise

        sync_config_generator(param, self.get_domain_name())

    def delete_interface(self,mac,force=False):

        status = self.status()
        if status == VIR_DOMAIN_PAUSED:
            self.resume()
            time.sleep(2)
            #raise KaresansuiVirtException("Domain %s is suspended." % self.get_domain_name())

        from karesansui.lib.virt.config import ConfigParam
        param = ConfigParam(self.get_domain_name())
        dom = self._conn.lookupByName(self.get_domain_name())

        xml_file = "%s/%s.xml" % (VIRT_XML_CONFIG_DIR, self.get_domain_name())
        if not os.path.exists(xml_file):
            ConfigFile(xml_file).write(dom.XMLDesc(0))
            if os.getuid() == 0 and os.path.exists(xml_file):
                r_chgrp(xml_file,KARESANSUI_GROUP)

        param.load_xml_config(xml_file)
        current_snapshot = param.get_current_snapshot()
        if force is True:
            param.load_xml_config(dom.XMLDesc(0))
            if current_snapshot is not None:
                param.set_current_snapshot(current_snapshot)

        for arr in param.interfaces:
            if arr["mac"] == mac:
                bridge = arr['bridge']
        mac = mac.lower()
        param.delete_interface(mac)

        try:
            from karesansui.lib.virt.config import XMLInterfaceConfigGenerator
            generator = XMLInterfaceConfigGenerator()
            generator.set_mac(mac)
            try:
                generator.set_bridge(bridge)
            except:
                pass
            cfg = generator.generate(None)
            """
            try:
                dom.detachDevice(cfg)
            except:
                xml_generator = XMLConfigGenerator()
                cfgxml = xml_generator.generate(param)
                self._conn.defineXML(cfgxml)
            """
            xml_generator = XMLConfigGenerator()
            cfgxml = xml_generator.generate(param)
            self._conn.defineXML(cfgxml)

            if status == VIR_DOMAIN_PAUSED:
                self.suspend()
        except:
            raise

        sync_config_generator(param, self.get_domain_name())

    def modify_mac_address(self,old,new):

        status = self.status()
        if status == VIR_DOMAIN_PAUSED:
            self.resume()
            time.sleep(2)
            #raise KaresansuiVirtException("Domain %s is suspended." % self.get_domain_name())

        from karesansui.lib.virt.config import ConfigParam
        param = ConfigParam(self.get_domain_name())
        dom = self._conn.lookupByName(self.get_domain_name())

        xml_file = "%s/%s.xml" % (VIRT_XML_CONFIG_DIR, self.get_domain_name())
        if not os.path.exists(xml_file):
            ConfigFile(xml_file).write(dom.XMLDesc(0))
            if os.getuid() == 0 and os.path.exists(xml_file):
                r_chgrp(xml_file,KARESANSUI_GROUP)
        param.load_xml_config(xml_file)

        new_interfaces = []

        old = old.lower()
        new = new.lower()
        for arr in param.interfaces:
            if arr["mac"] == old:
                bridge = arr['bridge']
                arr["mac"] = new
            new_interfaces.append(arr)
        param.interfaces = new_interfaces

        try:
            """
            try:
                self.delete_interface(old,True)
                self.append_interface(new,bridge)
            except:
                xml_generator = XMLConfigGenerator()
                cfgxml = xml_generator.generate(param)
                self._conn.defineXML(cfgxml)
            """
            xml_generator = XMLConfigGenerator()
            cfgxml = xml_generator.generate(param)
            self._conn.defineXML(cfgxml)

            if status == VIR_DOMAIN_PAUSED:
                self.suspend()
        except:
            raise

        sync_config_generator(param, self.get_domain_name())

    def set_memory(self,maxmem=None,memory=None):

        from karesansui.lib.virt.config import ConfigParam
        param = ConfigParam(self.get_domain_name())
        dom = self._conn.lookupByName(self.get_domain_name())

        xml_file = "%s/%s.xml" % (VIRT_XML_CONFIG_DIR, self.get_domain_name())
        if not os.path.exists(xml_file):
            ConfigFile(xml_file).write(dom.XMLDesc(0))
            if os.getuid() == 0 and os.path.exists(xml_file):
                r_chgrp(xml_file,KARESANSUI_GROUP)
        param.load_xml_config(xml_file)

        if maxmem:
            param.set_max_memory(maxmem)
        if memory:
            param.set_memory(memory)

        try:
            dom.setMemory(param.get_memory("k"))
            dom.setMaxMemory(param.get_max_memory("k"))
        except:
            raise

        sync_config_generator(param, self.get_domain_name())

    def set_vcpus(self,max_vcpus=None,vcpus=None):

        from karesansui.lib.virt.config import ConfigParam
        param = ConfigParam(self.get_domain_name())
        dom = self._conn.lookupByName(self.get_domain_name())

        xml_file = "%s/%s.xml" % (VIRT_XML_CONFIG_DIR, self.get_domain_name())
        if not os.path.exists(xml_file):
            ConfigFile(xml_file).write(dom.XMLDesc(0))
            if os.getuid() == 0 and os.path.exists(xml_file):
                r_chgrp(xml_file,KARESANSUI_GROUP)
        param.load_xml_config(xml_file)

        if max_vcpus is not None:
            param.set_max_vcpus(int(max_vcpus))

        if vcpus is not None:
            param.set_vcpus(int(vcpus))

        param.set_max_vcpus_limit(int(self.connection.get_max_vcpus()))
        param.set_vcpus_limit(int(self.get_vcpus_info()['max_vcpus']))

        try:
            dom.setVcpus(param.get_vcpus())
        except:
            raise

        sync_config_generator(param, self.get_domain_name())

    def set_vnc(self,port=None,listen=None,passwd=None,keymap=None):

        from karesansui.lib.virt.config import ConfigParam
        param = ConfigParam(self.get_domain_name())
        dom = self._conn.lookupByName(self.get_domain_name())

        xml_file = "%s/%s.xml" % (VIRT_XML_CONFIG_DIR, self.get_domain_name())
        if not os.path.exists(xml_file):
            ConfigFile(xml_file).write(dom.XMLDesc(0))
            if os.getuid() == 0 and os.path.exists(xml_file):
                r_chgrp(xml_file,KARESANSUI_GROUP)
        param.load_xml_config(xml_file)

        if port is not None:
            param.set_vnc_port(port)

        if listen is not None:
            param.set_vnc_listen(listen)

        if passwd is not None:
            param.set_vnc_passwd(passwd)

        if keymap is not None:
            param.set_vnc_keymap(keymap)

        sync_config_generator(param, self.get_domain_name())

    def is_creatable(self):
        """<comment-ja>
        ゲストOS(ドメイン)を起動することができるか。
        </comment-ja>
        <comment-en>
        TODO: English Comment
        </comment-en>
        """
        if self.status() == VIR_DOMAIN_SHUTOFF:
            return True
        else:
            return False

    def is_shutdownable(self):
        """<comment-ja>
        ゲストOS(ドメイン)をシャットダウンすることができるか。
        </comment-ja>
        <comment-en>
        TODO: English Comment
        </comment-en>
        """
        
        status = self.status()
        if status == VIR_DOMAIN_RUNNING \
               or status == VIR_DOMAIN_BLOCKED \
               or status == VIR_DOMAIN_PAUSED:
            return True
        else:
            return False

    def is_destroyable(self):
        """<comment-ja>
        ゲストOS(ドメイン)を強制停止することができるか。
        </comment-ja>
        <comment-en>
        TODO: English Comment
        </comment-en>
        """
        status = self.status()
        if status == VIR_DOMAIN_RUNNING \
               or status == VIR_DOMAIN_BLOCKED \
               or status == VIR_DOMAIN_PAUSED:
            return True
        else:
            return False

    def is_suspendable(self):
        """<comment-ja>
        ゲストOS(ドメイン)の一時停止することができるか。
        </comment-ja>
        <comment-en>
        TODO: English Comment
        </comment-en>
        """
        status = self.status()
        if status == VIR_DOMAIN_NOSTATE \
               or status ==VIR_DOMAIN_RUNNING \
               or status == VIR_DOMAIN_BLOCKED:
            return True
        else:
            return False

    def is_resumable(self):
        """<comment-ja>
        ゲストOS(ドメイン)再開することができるか。
        </comment-ja>
        <comment-en>
        TODO: English Comment
        </comment-en>
        """
        if self.status() == VIR_DOMAIN_PAUSED:
            return True
        else:
            return False

    def is_active(self):
        """<comment-ja>
        ゲストOSの状態がactiveか。
        </comment-ja>
        <comment-en>
        TODO: English Comment
        </comment-en>
        """
        return (self.get_domain_name() in self.connection.list_active_guest())

    def is_inactive(self):
        """<comment-ja>
        ゲストOSの状態がinactiveか。
        </comment-ja>
        <comment-en>
        TODO: English Comment
        </comment-en>
        """
        return (self.get_domain_name() in self.connection.list_inactive_guest())

    def is_takable_snapshot(self):
        """<comment-ja>
        スナップショットを作成できる状態か。
        </comment-ja>
        <comment-en>
        TODO: English Comment
        </comment-en>
        """
        if self.status() == VIR_DOMAIN_SHUTOFF:
            return False
        else:
            return True

    
class KaresansuiVirtNetwork:

    def __init__(self, conn, name=None):
        self.connection = conn
        self._conn = self.connection._conn
        self.set_network_name(name)

    def set_network_name(self,name=None):
        self.network_name = name
    def get_network_name(self):
        return self.network_name

    def load(self):
        param = NetworkConfigParam(self.get_network_name())
        param.load_xml_config("%s/%s.xml" % (VIRT_NETWORK_CONFIG_DIR, self.get_network_name()))

    def start(self):
        net = self._conn.networkLookupByName(self.get_network_name())
        try:
            net.create()
        except libvirt.libvirtError, e:
            raise KaresansuiVirtException(_("Could not start network '%s' (%s)") % (self.network_name, e))

    def stop(self):
        net = self._conn.networkLookupByName(self.get_network_name())
        try:
            net.destroy()
        except libvirt.libvirtError, e:
            raise KaresansuiVirtException(_("Could not stop network '%s' (%s)") % (self.network_name, e))

    def undefine(self):
        net = self._conn.networkLookupByName(self.get_network_name())
        net.undefine()

    def autostart(self, flag=None):
        net = self._conn.networkLookupByName(self.get_network_name())
        net.setAutostart(flag)

    def get_json(self):
        """<comment-ja>
        JSON形式でKaresansuiVirtNetwork情報を返却する。
        </comment-ja>
        <comment-en>
        TODO: English Comment
        </comment-en>
        """
        
        ret = {}
        ret['name'] = self.get_network_name()
        ret.update(self.get_info())
        return ret

    def get_info(self):
        try:
            net = self._conn.networkLookupByName(self.get_network_name())

            document = XMLParse(net.XMLDesc(0))
            autostart = net.autostart()
        except KaresansuiVirtException, e:
            return False

        name = XMLXpath(document,'/network/name/text()')
        uuid = XMLXpath(document,'/network/uuid/text()')
        bridge_name = XMLXpath(document,'/network/bridge/@name')
        bridge_stp = XMLXpath(document,'/network/bridge/@stp')
        bridge_forwardDelay = XMLXpath(document,'/network/bridge/@forwardDelay')
        bridge = {
                   "name": bridge_name,
                   "stp": bridge_stp,
                   "forwardDelay": bridge_forwardDelay,
                 }
        dhcp_range_start = XMLXpath(document,'/network/ip/dhcp/range/@start')
        dhcp_range_end = XMLXpath(document,'/network/ip/dhcp/range/@end')
        dhcp = {
                   "start": dhcp_range_start,
                   "end" : dhcp_range_end,
               }
        ip_address = XMLXpath(document,'/network/ip/@address')
        ip_netmask = XMLXpath(document,'/network/ip/@netmask')
        ip = {
                   "address": ip_address,
                   "netmask": ip_netmask,
                   "dhcp"   : dhcp,
             }
        forward_mode = XMLXpath(document,'/network/forward/@mode')
        forward_dev = XMLXpath(document,'/network/forward/@dev')
        forward = {
                   "mode": forward_mode,
                   "dev" : forward_dev,
             }

        is_active = self.is_active()

        return {
                "name"     : name,
                "uuid"     : uuid,
                "bridge"   : bridge,
                "dhcp"     : dhcp,
                "ip"       : ip,
                "forward"  : forward,
                "autostart": autostart,
                "is_active" : is_active,
        }

    def get_network_config_param(self):
        return NetworkConfigParam(self.get_info())

    def is_active(self):
        return (self.network_name in self._conn.listNetworks())

    def is_inactive(self):
        return (self.network_name in self._conn.listDefinedNetworks())

