示例#1
0
    def create(self, subnet, mask, start_ip=None, stop_ip=None):
        """Create a DHCP subnet; return DHCP subnet objects."""
        subnet = common.validate_ip_address(subnet)
        filter = 'cn=%s' % subnet
        if not common.is_number(mask):
            msg = 'Subnet mask must be an integer, dotted decimal (or any other\
 notation) is not allowed'

            self.log.error(msg)
            raise error.InputError(msg)
        mask = str(mask)
        if start_ip and not stop_ip:
            msg = 'A range must include a start and stop IP address'
            self.log.error(msg)
            raise error.InputError(msg)
        if start_ip is not None:
            start_ip = common.validate_ip_address(start_ip)
            stop_ip = common.validate_ip_address(stop_ip)
            start_ip, stop_ip = self._is_greater_ip_than(start_ip, stop_ip)

        dn = 'cn=%s,%s' % (subnet, self.dhcp_service_dn)
        dn_attr = {
            'objectClass': ['top', self.dhcp_subnet_class],
            'cn': [subnet],
            'dhcpNetMask': [mask]
        }
        if start_ip is not None:
            dn_attr['dhcpRange'] = start_ip + ' ' + stop_ip
        dn_info = [(k, v) for (k, v) in dn_attr.items()]
        result = self._create_object(dn, dn_info)
        self.log.debug('Result: %s' % result)
        return result
示例#2
0
def is_shell_safe(string):
    """Ensure input contains no dangerous characters."""
    max_length = 64
    string = str(string)
    pattern = re.compile('^[-_A-Za-z0-9 \.]+$')
    valid = pattern.match(string)
    if not valid:
        msg = '%s contains illegal characters' % string
        raise error.InputError(msg)
    if len(string) > max_length:
        msg = '%s cannot be longer than %s' % (string, max_length)
        raise error.InputError(msg)
    return string
示例#3
0
def validate_domain(domain_name):
    msg = '%s is not a valid domain name' % domain_name
    if domain_name is None:
        raise error.InputError(msg)
    domain_name = domain_name.lower()
    if domain_name[-1:] == ".":
        domain_name = domain_name[:-1]  # strip dot from the right
    if len(domain_name) > 255:
        raise error.InputError(msg)
    pattern = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
    for x in domain_name.split("."):
        valid = pattern.match(x)
        if not valid:
            raise error.InputError(msg)
    return domain_name
示例#4
0
文件: ip.py 项目: mattmb/spoke
    def create(self, aloc_ips=None):
        """Create subnet kv stores; populate with IPs; return True."""
        if not (self.network and self.mask):
            msg = 'Please specify ip and mask'
            raise error.InputError(msg)

        if self.KV.exists(self.kv_aloc) or self.KV.exists(self.kv_free):
            msg = 'Subnet %s/%s already exists' % (self.kv_name, str(
                self.mask))
            raise error.AlreadyExists(msg)

        self._populate_aloc_ips(aloc_ips)
        self._populate_free_ips()

        msg = 'Created subnet %s/%s with %s free and %s reserved IPs' \
        % (self.kv_name, str(self.mask), len(self.free_ips), len(self.aloc_ips))
        self.log.debug(msg)
        result = self.get()
        if result['exit_code'] == 0 and result['count'] == 1:
            result['msg'] = "Created %s:" % result['type']
            return result
        else:
            msg = 'Create operation returned OK, but unable to find object'
            raise error.NotFound(msg)
        return result
示例#5
0
 def _get_type_attr(self, type):
     """Validate resource type; return resource type's LDAP attribute."""
     if type in self.dns_type_attrs:
         return self.dns_type_attrs[type]
     else:
         msg = 'Unknown DNS resource type'
         raise error.InputError(msg)
示例#6
0
文件: host.py 项目: KrisSaxton/spoke
    def create(self, uuid_start=None, get_mac=False):
        """Create initial UUID object; return True."""
        self.log.debug('Running UUID create with get_mac set to %s' % get_mac)
        if uuid_start:
            self.next_uuid_start = uuid_start
        if not common.is_number(self.next_uuid_start):
            msg = 'next_uuid_start must be an integer'
            raise error.InputError(msg)
        # Now we know it's an integer, make it a string for LDAP's sake
        self.next_uuid_start = str(self.next_uuid_start)
        dn = self.next_uuid_dn
        dn_info = []
        if not self.next_uuid_class in self.next_uuid_classes:
            dn_info.append((0, 'objectClass', self.next_uuid_class))
        if not self.next_uuid_attr in self.next_uuid_attrs:
            dn_info.append((0, self.next_uuid_attr, self.next_uuid_start))

        if dn_info == []:
            msg = 'UUID entry already set on %s.' % dn
            raise error.AlreadyExists(msg)
        self.log.debug('Adding %s to %s ' % (dn_info, dn))
        result = self._create_object(dn, dn_info)
        uuid = int(result['data'][0][1][self.next_uuid_attr][0])
        mac = common.mac_from_uuid(uuid, 0)
        if get_mac:
            result['data'] = (uuid, mac)
        else:
            result['data'] = [uuid]
        result['msg'] = 'Created UUID:'
        self.log.debug('Result: %s' % result)
        return result
示例#7
0
 def _validate_number(self, name, number):
     try:
         int(number)
     except:
         msg = '%s must be an integer, you passed %s' % (name, number)
         self.log.error(msg)
         raise error.InputError(msg)
     return number
示例#8
0
def validate_ip_address(ip):
    """Ensure input is a valid IP address."""
    ip = str(ip)
    pattern = re.compile(r"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")
    valid = pattern.match(ip)
    if not valid:
        msg = '%s is not a valid IP address' % ip
        raise error.InputError(msg)
    return ip
示例#9
0
def validate_storage_format(size):
    """Ensure input is a valid storage value."""
    size = str(size)
    pattern = re.compile('^[0-9]{1,3}[kKmMgG]$')
    valid = pattern.match(size)
    if not valid:
        msg = '%s is not a valid storage format' % size
        raise error.InputError(msg)
    return size
示例#10
0
def validate_email_address(email_addr):
    """Ensure input is a valid email address format."""
    email_addr = email_addr.lower()
    pattern = re.compile(r"^[-a-z0-9_.]+@[-a-z0-9]+\.+[a-z]{2,6}")
    valid_email = pattern.match(email_addr)
    if not valid_email:
        msg = '%s is not a valid email address' % email_addr
        raise error.InputError(msg)
    return email_addr
示例#11
0
文件: mbx.py 项目: KrisSaxton/spoke
 def _validate_mailbox_name(self, mailbox_name):
     """Ensure input is a valid email address format."""
     mailbox_name = mailbox_name.lower()
     pattern = re.compile(r"^[-a-z0-9_.]+@[-a-z0-9]+\.+[a-z]{2,6}")
     valid_mailbox = pattern.match(mailbox_name)
     if not valid_mailbox:
         msg = '%s is not a valid mailbox name' % mailbox_name
         raise error.InputError(msg)
     return mailbox_name
示例#12
0
def is_shell_safe(string):
    """Ensure input contains no dangerous characters."""
    string = str(string)
    pattern = re.compile('^[-_A-Za-z0-9 \.]+$')
    valid = pattern.match(string)
    if not valid:
        msg = '%s contains illegal characters' % string
        raise error.InputError(msg)
    return string
示例#13
0
def validate_host_family(family):
    if family is None:
        msg = "Please specify host family; must be xen or kvm or vmware."
        raise error.InputError, msg
    pattern = re.compile('^(test|xen|kvm|vmware)$')
    valid_family = pattern.match(family)
    if not valid_family:
        msg = "%s is not a valid host family; must be xen, kvm or vmware" % family
        raise error.InputError(msg)
    return family
示例#14
0
 def _validate_input(self, entry):
     """Check input and add trailing period to hostname."""
     entry_list = entry.split(' ')
     if len(entry_list) > 2:
         msg = 'Too many entries: do you have a space somewhere?'
         self.log.error(msg)
         raise error.InputError(msg)
     if len(entry_list) < 2:
         msg = 'Too few entries: are you missing the priority?'
         self.log.error(msg)
         raise error.InputError(msg)
     priority = entry_list[0]
     hostname = entry_list[1]
     try:
         int(priority)
     except:
         msg = 'MX record priority:%s must be an integer.' % priority
         self.log.error(msg)
         raise error.InputError(msg)
     hostname = common.validate_domain(hostname)
     return priority + ' ' + hostname + '.'
示例#15
0
文件: ip.py 项目: mattmb/spoke
 def modify(self, reserve=False, release=False):
     """Reserve or release IP address from Subnet"""
     if not (self.network and self.mask):
         msg = 'Please specify ip and mask'
         raise error.InputError(msg)
     if not reserve and not release:
         msg = 'You must specify if you wish to reserve or release an IP'
         raise error.InputError(msg)
     if reserve and release:
         msg = 'You cannot simultaneously reserve and release an IP'
         raise error.InputError(msg)
     if reserve:
         offer = self._reserve_ip(reserve)
         result = common.process_results(offer)
         result['msg'] = 'Reserved ip(s) %s from %s' % (offer, self.kv_name)
         self.log.debug('Result: %s' % result)
         return result
     if release:
         self._release_ip(release)
         result = self.get()
         result['msg'] = 'Returned %s ip(s) to %s' % (release, self.kv_name)
         self.log.debug('Result: %s' % result)
         return result
示例#16
0
 def _is_greater_ip_than(self, start_ip, stop_ip):
     """Ensure the last ip is greater than the first."""
     start_ip_list = start_ip.split('.')
     stop_ip_list = stop_ip.split('.')
     index = 0
     while index < len(start_ip_list):
         if start_ip_list[index] != stop_ip_list[index]:
             # Found non match
             if int(start_ip_list[index]) > int(stop_ip_list[index]):
                 msg = '%s is greater than %s' % (start_ip, stop_ip)
                 self.log.error(msg)
                 raise error.InputError(msg)
                 # We only care about the first match
             break
         index = index + 1
     return start_ip, stop_ip
示例#17
0
 def create(self, host_name):
     """Create DHCP host; return DHCP host objects."""
     filter = 'cn=%s' % host_name
     if self.dhcp_server == host_name:
         msg = 'DHCP hostname %s with same name as DHCP server %s' % \
                                             (host_name, self.dhcp_server)
         self.log.error(msg)
         raise error.InputError(msg)
     dn = 'cn=%s,%s' % (host_name, self.dhcp_group_dn)
     dn_attr = {
         'objectClass':
         ['top', self.dhcp_host_class, self.dhcp_options_class],
         'cn': [host_name]
     }
     dn_info = [(k, v) for (k, v) in dn_attr.items()]
     result = self._create_object(dn, dn_info)
     self.log.debug('Result: %s' % result)
     return result
示例#18
0
文件: ip.py 项目: mattmb/spoke
 def delete(self):
     """Delete subnet kv stores; return True."""
     if not (self.network and self.mask):
         msg = 'Please specify ip and mask'
         raise error.InputError(msg)
     if self.get()['data'] == []:
         msg = "cannot delete as already missing"
         raise error.NotFound, msg
     # Delete kv stores
     self.KV.delete(self.kv_aloc)
     self.KV.delete(self.kv_free)
     result = self.get()
     if result['exit_code'] == 3 and result['count'] == 0:
         result['msg'] = "Deleted %s:" % result['type']
         return result
     else:
         msg = 'Delete operation returned OK, but object still there?'
         raise error.SearchError(msg)
示例#19
0
文件: ip.py 项目: mattmb/spoke
    def __init__(self, ip=None, mask=None, dc=None):
        """Get config, setup logging and Redis connection."""
        SpokeKV.__init__(self)
        self.config = config.setup()
        self.log = logger.setup(__name__)
        self.max_mask = 16  # This is the largest network we can work with
        # Check our subnet is well formatted in dotted decimal
        if ip and mask:
            common.validate_ip_address(ip)
            # Check our netmask is well formatted and NOT in dotted decimal
            try:
                common.validate_ip_address(mask)
            except:
                pass  # It's not a dotted decimal format subnet, good
            else:
                # It validated as a dotted decimal, but we need an integer
                msg = 'IPv4 subnet mask must be between %s and 32' % self.max_mask
                raise error.InputError(msg)

            self.subnet = ip_helper.Network(ip, int(mask))
            self.network = self.subnet.network()
            self.mask = self.subnet.mask

            if dc is not None:
                self.kv_name = dc + str(self.network)
                self.kv_free = '%s:%s:%s:free' % (dc, self.network, self.mask)
                self.kv_aloc = '%s:%s:%s:aloc' % (dc, self.network, self.mask)
            else:
                self.kv_name = str(self.network)
                self.kv_free = '%s:%s:free' % (self.network, self.mask)
                self.kv_aloc = '%s:%s:aloc' % (self.network, self.mask)
            self.ip_ldap_enabled = self.config.get('IP', 'ip_ldap_enabled',
                                                   False)
            self.ip_ldap_attr = self.config.get('IP', 'ip_ldap_attr',
                                                'dhcpStatements')
            self.ip_ldap_key = self.config.get('IP', 'ip_ldap_key',
                                               'fixed-address')
            self.ip_ldap_search_base = self.config.get('IP',
                                                       'ip_ldap_search_base',
                                                       False)
        else:
            (self.network, self.mask) = (None, None)
示例#20
0
 def modify(self, list_address, enable):
     """Enable/Disable a mailing list; return True."""
     list_address = self._validate_input(list_address)
     list_info = self.get(list_address)
     if list_info['data'] == []:
         msg = 'Unable to modify mailing list access, no list found.'
         raise error.NotFound(msg)
     dn = list_info['data'][0].__getitem__(0)
     old_result = list_info['data'][0].__getitem__(1)
     old_attrs = {self.list_enable_attr: old_result[self.list_enable_attr]}
     if enable == True:
         new_attrs = {self.list_enable_attr: 'TRUE'}
     elif enable == False:
         new_attrs = {self.list_enable_attr: 'FALSE'}
     else:
         msg = 'enable can only be one of True or False'
         raise error.InputError(msg)
     result = self._modify_attributes(dn, new_attrs, old_attrs)
     self.log.debug('Result: %s' % result)
     return result
示例#21
0
文件: ip.py 项目: mattmb/spoke
    def _populate_free_ips(self):
        """Populate KV store with all free IP within a given subnet."""
        all_ips = set()
        # /8 network takes 1h 9m (2Ghz CPU and 4GB RAM); produces DB of 220MB
        if self.mask < self.max_mask:
            msg = 'Subnets larger than %s must be created manually' % self.mask
            raise error.InputError(msg)
        for ip in self.subnet:
            all_ips.add(str(ip))
        self.free_ips = all_ips - self.aloc_ips

        for free_ip in self.free_ips:
            self.KV.sadd(self.kv_free, free_ip)
        # Remove the network and broadcast addresses
        self.KV.srem(self.kv_free, self.subnet.network())
        self.KV.srem(self.kv_free, self.subnet.broadcast())
        msg = 'KV store %s populated with %s free IP addresses' % \
            (self.kv_free, len(self.free_ips))
        self.log.debug(msg)
        return True
示例#22
0
文件: vcs.py 项目: mattmb/spoke
 def modify(self, enable):
     """Modify a user account's repository access; return True."""
     svn_info = self.get()['data']
     if svn_info == []:
         msg = 'Unable to modify repository access, no repositories found.'
         raise error.NotFound(msg)
     dn = svn_info[0].__getitem__(0)
     old_result = svn_info[0].__getitem__(1)
     old_attrs = {self.svn_enable_attr: old_result[self.svn_enable_attr]}
     if enable == True:
         new_attrs = {self.svn_enable_attr: 'TRUE'}
     elif enable == False:
         new_attrs = {self.svn_enable_attr: 'FALSE'}
     else:
         msg = 'enable can only be one of True or False'
         raise error.InputError(msg)
     self.log.debug('Modifying %s from %s to %s' %
                    (dn, old_attrs, new_attrs))
     result = self._modify_attributes(dn, new_attrs, old_attrs)
     self.log.debug('Result: %s' % result)
     return result
示例#23
0
文件: user.py 项目: mattmb/spoke
 def get(self, first=None, last=None, unique=False):
     """Retrieve a user account; return user object."""
     if first is None and last is None:
         if unique:
             raise error.InputError('You must target a specific user in \
             order to search for a unique value')
         filter = '%s=*' % self.user_key # Return a list of all users
     else:
         self._gen_user_info(first, last)
         filter = '%s=%s' % (self.user_key, self.user_id)
     if unique: 
         trueorfalse = True
     else:
         trueorfalse = False
     msg = 'Searching at %s with scope %s and filter %s' % \
         (self.org_dn, self.search_scope, filter)
     self.log.debug(msg)
     result = self._get_object(self.org_dn, self.search_scope, \
                               filter, unique=trueorfalse)
     self.log.debug('Result: %s' % result)
     return result
示例#24
0
 def delete(self, vm_name):
     '''Remove a definition from store, will fail on xen if machine is running'''
     if vm_name == None:
         msg = "InputError: vm name must be specified with delete."
         raise error.InputError(msg)
     try:
         dom = self.conn.lookupByName(vm_name)
     except libvirt.libvirtError:
         msg = "VM definition for %s doesn't exist, can't delete." % vm_name
         raise error.NotFound(msg)
     try:
         dom.undefine()
     except libvirt.libvirtError:
         msg = "VM %s is running (shutdown first?), can't delete." % vm_name
         raise error.VMRunning(msg)
     #self.conn.close()
     result = self.get(vm_name)
     if result['exit_code'] == 3 and result['count'] == 0:
         result['msg'] = "Deleted %s:" % result['type']
         return result
     else:
         msg = 'Delete operation returned OK, but object still there?'
         raise error.SearchError(msg)
示例#25
0
    def create(self, vm_name, vm_uuid, vm_mem, vm_cpu, vm_family, vm_storage_layout,
               vm_network_layout, vm_install=False, vm_disks=None, vm_interfaces=None):
        """Define a new VM and add to hypervisor's store (does not start)."""
        try:
            vm_name = common.validate_hostname(vm_name)
            vm_cpu = common.validate_cpu(vm_cpu)
            vm_mem = common.validate_mem(vm_mem)
            #vm_type = common.validate_host_type(vm_type)
            vm_family = common.validate_host_family(vm_family)
            #vm_extra_opts = common.is_shell_safe(vm_extra_opts)
            vm_uuid = common.validate_uuid(vm_uuid)
        except error.InputError as e:
            self.log.error(e)
            raise e
        
        try:
            self.conn.lookupByName(vm_name)
        except libvirt.libvirtError:
            pass
        else:
            msg = "Domain %s already exists, cannot create." % vm_name
            raise error.AlreadyExists(msg)
        
        # Create a UUID in hypervisor format
        formatted_uuid = self._format_uuid(vm_uuid)
        
        #-1 means XEN will give the right XenID when it starts
        vm_id=-1
        
        #Initial xml structure
        doc = xml.createDoc("doc")
        domain = xml.createElement(doc, "domain", {"type": vm_family})
        #Variable config options
        #xml.createChild(doc, domain, "arch name", None, 'i686')
        xml.createChild(doc, domain, "name", None, vm_name)
        xml.createChild(doc, domain, "memory", None, vm_mem)
        xml.createChild(doc, domain, "currentMemory", None, vm_mem)
        xml.createChild(doc, domain, "vcpu", None, vm_cpu)
        xml.createChild(doc, domain, "uuid", None, formatted_uuid)
        
        #fixed(ish) config options
        os = xml.createChild(doc, domain, "os", None, None)
        #ks - the below is going to have to change for 64bit
        xml.createChild(doc, os, "type", {"arch": "i686"}, "hvm")
        xml.createChild(doc, domain, "clock", {"offset": "utc"}, None)
        xml.createChild(doc, domain, "on_poweroff", None, "destroy")
        xml.createChild(doc, domain, "on_reboot", None, "restart")
        xml.createChild(doc, domain, "on_crash", None, "restart")
        
        devices = xml.createChild(doc, domain, "devices", None, None)
        console = xml.createChild(doc, devices, "console", {"type": "pty"}, None)
        xml.createChild(doc, console, "target", {"type": "xen", "port": "0"}, None)
        #ks
        #xml.createChild(doc, devices, "input", {"type": "mouse", "bus": "xen"}, None)
        # TODO Change the port such that it is associated with the UUID and change listen to internal interface only
        xml.createChild(doc, devices, "graphics", {"type": "vnc", "port": "-1", "autoport": "yes", "listen": "0.0.0.0"}, None)
        xml.createChild(doc, devices, "emulator", None, "/usr/lib/xen/bin/qemu-dm")
        
#        #parse disk info
#        for item in vm_disks:
#            #local1 means hda and vg01
#            if item[0] == "local1":
#                disk = xml.createChild(doc, devices, "disk", {"type": "block", "device": "disk"}, None)
#                xml.createChild(doc, disk, "driver", {"name": "phy"}, None)
#                xml.createChild(doc, disk, "source", {"dev": "/dev/vg01/%s" % vm_name}, None)
#                xml.createChild(doc, disk, "target", {"dev": "hda", "bus": "ide"}, None)
#            #local2 means hdb and vg02
#            if item[0] == "local2":
#                disk = xml.createChild(doc, devices, "disk", {"type": "block", "device": "disk"}, None)
#                xml.createChild(doc, disk, "driver", {"name": "phy"}, None)
#                xml.createChild(doc, disk, "source", {"dev": "/dev/vg01/ko-test-02"}, None)
#                xml.createChild(doc, disk, "target", {"dev": "hdb", "bus": "ide"}, None)                                                      

        if vm_disks is not None:
            for item in vm_disks:
                if item[0] == "local1":
                    disk = xml.createChild(doc, devices, "disk", {"type": "block", "device": "disk"}, None)
                    xml.createChild(doc, disk, "driver", {"name": "phy"}, None)
                    xml.createChild(doc, disk, "source", {"dev": "/dev/vg01/%s" % vm_name}, None)
                    xml.createChild(doc, disk, "target", {"dev": "hda", "bus": "ide"}, None)
                #local2 means hdb and vg02
                if item[0] == "local2":
                    disk = xml.createChild(doc, devices, "disk", {"type": "block", "device": "disk"}, None)
                    xml.createChild(doc, disk, "driver", {"name": "phy"}, None)
                    xml.createChild(doc, disk, "source", {"dev": "/dev/vg02/%s" % vm_name}, None)
                    xml.createChild(doc, disk, "target", {"dev": "hdb", "bus": "ide"}, None)                                                      

        elif vm_storage_layout is not None:
            try:
                disks = self.dtypes[vm_storage_layout]
            except KeyError as e:
                msg = "The disk type %s is not present in config file." % e
                raise error.InputError, msg
            for item in disks:
                item = common.validate_disks_in_conf(self.dnames[item])
                hv_dev = item[0] + "/" + vm_name
                dom_dev = item[1]
                disk = xml.createChild(doc, devices, "disk", {"type": "block", "device": "disk"}, None)
                xml.createChild(doc, disk, "driver", {"name": "phy"}, None)
                xml.createChild(doc, disk, "source", {"dev": hv_dev}, None)
                xml.createChild(doc, disk, "target", {"dev": dom_dev, "bus": "ide"}, None)                                                      

        #parse interface info
        if vm_interfaces is not None:
            for interface in vm_interfaces:
                #get input from interface list
                bridge = int( interface[0].lstrip('breth') )
                mac = interface[1]
                source_interface = interface[2]
                
                interface = xml.createChild(doc, devices, "interface", {"type": "bridge"}, None)
                xml.createChild(doc, interface, "mac", {"address": mac}, None)
                xml.createChild(doc, interface, "source", {"bridge": source_interface}, None)
                xml.createChild(doc, interface, "script", {"path": "vif-bridge"}, None)
                xml.createChild(doc, interface, "target", {"dev": "vif%i.%i" % (vm_id, bridge)}, None)
        elif vm_network_layout is not None:
            try:
                interfaces = self.ifacedef[vm_network_layout]
            except KeyError:
                msg = "The interface type %s is not present in config file." % vm_network_layout
                raise error.InputError(msg)
            
            # Ensure that br0,x is done first as xen cares about order in xml.
            interfaces = sorted(interfaces, key=itemgetter(0))
            for interface in interfaces:
                interface = common.validate_interfaces_in_conf(interface)
                iface_number = int( interface[0].lstrip('breth') )
                if iface_number == 0:
                    boot_mac = common.mac_from_uuid(vm_uuid, iface_number)                   
                    boot_int = interface[1]
                mac = common.mac_from_uuid(vm_uuid, iface_number)
                                   
                source_interface = interface[1]
                # KS enumerate avail interfaces via facter, not remote socket op 
                #if not source_interface in self._all_interfaces():
                #    msg = "%s does not exist on this machine so we cant bridge to it!" % source_interface
                #    raise error.InsufficientResource, msg
                                    
                interface = xml.createChild(doc, devices, "interface", {"type": "bridge"}, None)
                xml.createChild(doc, interface, "mac", {"address": mac}, None)
                xml.createChild(doc, interface, "source", {"bridge": source_interface}, None)
                xml.createChild(doc, interface, "script", {"path": "vif-bridge"}, None)
                xml.createChild(doc, interface, "target", {"dev": "vif%i.%i" % (vm_id, iface_number)}, None)
        
        if vm_install: # Add network boot lines
            xml.createChild(doc, domain, "bootloader", None, "/usr/sbin/pypxeboot" )
            try:
                xml.createChild(doc, domain, "bootloader_args", None, "--udhcpc=/usr/local/pkg/udhcp/sbin/udhcpc --interface=%s mac=%s --label=install-aethernet" % (boot_int, boot_mac) )
            except UnboundLocalError:
                msg = "In config there must be an interface br0 as the provisioning interface!"
                raise error.ConfigError(msg)
        else:
            xml.createChild(doc, domain, "bootloader", None, "/usr/bin/pygrub" )

        try:
            out = self.conn.defineXML(xml.out(doc))
        except Exception, e:
            trace = traceback.format_exc()
            raise error.LibvirtError(e, trace)