Josh's networking refactor, modified to work with projects
This commit is contained in:
@@ -1,25 +1,11 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright [2010] [Anso Labs, LLC]
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
import os
|
||||
import signal
|
||||
import os
|
||||
import nova.utils
|
||||
import subprocess
|
||||
|
||||
from nova import utils
|
||||
|
||||
# todo(ja): does the definition of network_path belong here?
|
||||
|
||||
from nova import flags
|
||||
@@ -30,13 +16,13 @@ def execute(cmd):
|
||||
logging.debug("FAKE NET: %s" % cmd)
|
||||
return "fake", 0
|
||||
else:
|
||||
utils.execute(cmd)
|
||||
return nova.utils.execute(cmd)
|
||||
|
||||
def runthis(desc, cmd):
|
||||
if FLAGS.fake_network:
|
||||
execute(cmd)
|
||||
return execute(cmd)
|
||||
else:
|
||||
utils.runthis(desc,cmd)
|
||||
return nova.utils.runthis(desc,cmd)
|
||||
|
||||
def Popen(cmd):
|
||||
if FLAGS.fake_network:
|
||||
@@ -61,44 +47,46 @@ def bind_public_ip(ip, interface):
|
||||
|
||||
def vlan_create(net):
|
||||
""" create a vlan on on a bridge device unless vlan already exists """
|
||||
if not device_exists("vlan%s" % net.vlan):
|
||||
if not device_exists("vlan%s" % net['vlan']):
|
||||
logging.debug("Starting VLAN inteface for %s network", (net['vlan']))
|
||||
execute("sudo vconfig set_name_type VLAN_PLUS_VID_NO_PAD")
|
||||
execute("sudo vconfig add %s %s" % (net.bridge_dev, net.vlan))
|
||||
execute("sudo ifconfig vlan%s up" % (net.vlan))
|
||||
execute("sudo vconfig add %s %s" % (FLAGS.bridge_dev, net['vlan']))
|
||||
execute("sudo ifconfig vlan%s up" % (net['vlan']))
|
||||
|
||||
def bridge_create(net):
|
||||
""" create a bridge on a vlan unless it already exists """
|
||||
if not device_exists(net.bridge_name):
|
||||
execute("sudo brctl addbr %s" % (net.bridge_name))
|
||||
if not device_exists(net['bridge_name']):
|
||||
logging.debug("Starting Bridge inteface for %s network", (net['vlan']))
|
||||
execute("sudo brctl addbr %s" % (net['bridge_name']))
|
||||
# execute("sudo brctl setfd %s 0" % (net.bridge_name))
|
||||
# execute("sudo brctl setageing %s 10" % (net.bridge_name))
|
||||
execute("sudo brctl stp %s off" % (net.bridge_name))
|
||||
execute("sudo brctl addif %s vlan%s" % (net.bridge_name, net.vlan))
|
||||
execute("sudo brctl stp %s off" % (net['bridge_name']))
|
||||
execute("sudo brctl addif %s vlan%s" % (net['bridge_name'], net['vlan']))
|
||||
if net.bridge_gets_ip:
|
||||
execute("sudo ifconfig %s %s broadcast %s netmask %s up" % \
|
||||
(net.bridge_name, net.gateway, net.broadcast, net.netmask))
|
||||
confirm_rule("FORWARD --in-interface %s -j ACCEPT" % (net.bridge_name))
|
||||
(net['bridge_name'], net.gateway, net.broadcast, net.netmask))
|
||||
confirm_rule("FORWARD --in-interface %s -j ACCEPT" % (net['bridge_name']))
|
||||
else:
|
||||
execute("sudo ifconfig %s up" % net.bridge_name)
|
||||
execute("sudo ifconfig %s up" % net['bridge_name'])
|
||||
|
||||
def dnsmasq_cmd(net):
|
||||
cmd = ['sudo dnsmasq',
|
||||
' --strict-order',
|
||||
' --bind-interfaces',
|
||||
' --conf-file=',
|
||||
' --pid-file=%s' % dhcp_file(net.vlan, 'pid'),
|
||||
' --pid-file=%s' % dhcp_file(net['vlan'], 'pid'),
|
||||
' --listen-address=%s' % net.dhcp_listen_address,
|
||||
' --except-interface=lo',
|
||||
' --dhcp-range=%s,%s,120s' % (net.dhcp_range_start, net.dhcp_range_end),
|
||||
' --dhcp-range=%s,static,120s' % (net.dhcp_range_start),
|
||||
' --dhcp-lease-max=61',
|
||||
' --dhcp-hostsfile=%s' % dhcp_file(net.vlan, 'conf'),
|
||||
' --dhcp-leasefile=%s' % dhcp_file(net.vlan, 'leases')]
|
||||
' --dhcp-hostsfile=%s' % dhcp_file(net['vlan'], 'conf'),
|
||||
' --dhcp-leasefile=%s' % dhcp_file(net['vlan'], 'leases')]
|
||||
return ''.join(cmd)
|
||||
|
||||
def hostDHCP(network, host):
|
||||
idx = host['address'].split(".")[-1] # Logically, the idx of instances they've launched in this net
|
||||
def hostDHCP(network, host, mac):
|
||||
idx = host.split(".")[-1] # Logically, the idx of instances they've launched in this net
|
||||
return "%s,%s-%s-%s.novalocal,%s" % \
|
||||
(host['mac'], host['user_id'], network.vlan, idx, host['address'])
|
||||
(mac, network['user_id'], network['vlan'], idx, host)
|
||||
|
||||
# todo(ja): if the system has restarted or pid numbers have wrapped
|
||||
# then you cannot be certain that the pid refers to the
|
||||
@@ -111,9 +99,9 @@ def start_dnsmasq(network):
|
||||
if a dnsmasq instance is already running then send a HUP
|
||||
signal causing it to reload, otherwise spawn a new instance
|
||||
"""
|
||||
with open(dhcp_file(network.vlan, 'conf'), 'w') as f:
|
||||
with open(dhcp_file(network['vlan'], 'conf'), 'w') as f:
|
||||
for host_name in network.hosts:
|
||||
f.write("%s\n" % hostDHCP(network, network.hosts[host_name]))
|
||||
f.write("%s\n" % hostDHCP(network, host_name, network.hosts[host_name]))
|
||||
|
||||
pid = dnsmasq_pid_for(network)
|
||||
|
||||
@@ -123,12 +111,11 @@ def start_dnsmasq(network):
|
||||
# correct dnsmasq process
|
||||
try:
|
||||
os.kill(pid, signal.SIGHUP)
|
||||
return
|
||||
except Exception, e:
|
||||
logging.debug("Hupping dnsmasq threw %s", e)
|
||||
|
||||
# otherwise delete the existing leases file and start dnsmasq
|
||||
lease_file = dhcp_file(network.vlan, 'leases')
|
||||
lease_file = dhcp_file(network['vlan'], 'leases')
|
||||
if os.path.exists(lease_file):
|
||||
os.unlink(lease_file)
|
||||
|
||||
@@ -156,7 +143,7 @@ def dnsmasq_pid_for(network):
|
||||
if machine has rebooted pid might be incorrect (caller should check)
|
||||
"""
|
||||
|
||||
pid_file = dhcp_file(network.vlan, 'pid')
|
||||
pid_file = dhcp_file(network['vlan'], 'pid')
|
||||
|
||||
if os.path.exists(pid_file):
|
||||
with open(pid_file, 'r') as f:
|
||||
|
||||
@@ -17,15 +17,16 @@
|
||||
Classes for network control, including VLANs, DHCP, and IP allocation.
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
|
||||
# TODO(termie): clean up these imports
|
||||
from nova import vendor
|
||||
import IPy
|
||||
|
||||
from nova import datastore
|
||||
import nova.exception
|
||||
from nova.compute import exception
|
||||
from nova import flags
|
||||
from nova import utils
|
||||
@@ -34,145 +35,129 @@ from nova.auth import users
|
||||
import linux_net
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
flags.DEFINE_string('net_libvirt_xml_template',
|
||||
utils.abspath('compute/net.libvirt.xml.template'),
|
||||
'Template file for libvirt networks')
|
||||
flags.DEFINE_string('networks_path', utils.abspath('../networks'),
|
||||
'Location to keep network config files')
|
||||
flags.DEFINE_integer('public_vlan', 1, 'VLAN for public IP addresses')
|
||||
flags.DEFINE_string('public_interface', 'vlan1', 'Interface for public IP addresses')
|
||||
flags.DEFINE_string('public_interface', 'vlan1',
|
||||
'Interface for public IP addresses')
|
||||
flags.DEFINE_string('bridge_dev', 'eth1',
|
||||
'network device for bridges')
|
||||
flags.DEFINE_integer('vlan_start', 100, 'First VLAN for private networks')
|
||||
flags.DEFINE_integer('vlan_end', 4093, 'Last VLAN for private networks')
|
||||
flags.DEFINE_integer('network_size', 256, 'Number of addresses in each private subnet')
|
||||
flags.DEFINE_integer('network_size', 256,
|
||||
'Number of addresses in each private subnet')
|
||||
flags.DEFINE_string('public_range', '4.4.4.0/24', 'Public IP address block')
|
||||
flags.DEFINE_string('private_range', '10.0.0.0/8', 'Private IP address block')
|
||||
|
||||
|
||||
# HACK(vish): to delay _get_keeper() loading
|
||||
def _get_keeper():
|
||||
if _get_keeper.keeper == None:
|
||||
_get_keeper.keeper = datastore.Keeper(prefix="net")
|
||||
return _get_keeper.keeper
|
||||
_get_keeper.keeper = None
|
||||
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
|
||||
# CLEANUP:
|
||||
# TODO(ja): use singleton for usermanager instead of self.manager in vlanpool et al
|
||||
# TODO(ja): does vlanpool "keeper" need to know the min/max - shouldn't FLAGS always win?
|
||||
|
||||
class Network(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.bridge_gets_ip = False
|
||||
try:
|
||||
os.makedirs(FLAGS.networks_path)
|
||||
except Exception, err:
|
||||
pass
|
||||
self.load(**kwargs)
|
||||
|
||||
def to_dict(self):
|
||||
return {'vlan': self.vlan,
|
||||
'network': self.network_str,
|
||||
'hosts': self.hosts}
|
||||
|
||||
def load(self, **kwargs):
|
||||
self.network_str = kwargs.get('network', "192.168.100.0/24")
|
||||
self.hosts = kwargs.get('hosts', {})
|
||||
self.vlan = kwargs.get('vlan', 100)
|
||||
self.name = "nova-%s" % (self.vlan)
|
||||
self.network = IPy.IP(self.network_str)
|
||||
self.gateway = self.network[1]
|
||||
self.netmask = self.network.netmask()
|
||||
self.broadcast = self.network.broadcast()
|
||||
self.bridge_name = "br%s" % (self.vlan)
|
||||
|
||||
def __str__(self):
|
||||
return json.dumps(self.to_dict())
|
||||
|
||||
def __unicode__(self):
|
||||
return json.dumps(self.to_dict())
|
||||
class BaseNetwork(datastore.RedisModel):
|
||||
bridge_gets_ip = False
|
||||
object_type = 'network'
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, args):
|
||||
for arg in args.keys():
|
||||
value = args[arg]
|
||||
del args[arg]
|
||||
args[str(arg)] = value
|
||||
self = cls(**args)
|
||||
return self
|
||||
def get_all_hosts(cls):
|
||||
for vlan in get_assigned_vlans().values():
|
||||
network_str = get_subnet_from_vlan(vlan)
|
||||
for addr in datastore.Redis.instance().hgetall(
|
||||
"network:%s:hosts" % (network_str)):
|
||||
yield addr
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_string):
|
||||
parsed = json.loads(json_string)
|
||||
return cls.from_dict(parsed)
|
||||
def create(cls, user_id, project_id, security_group, vlan, network_str):
|
||||
network_id = "%s:%s" % (project_id, security_group)
|
||||
net = cls(network_id, network_str)
|
||||
net['user_id'] = user_id
|
||||
net['project_id'] = project_id
|
||||
net["vlan"] = vlan
|
||||
net["bridge_name"] = "br%s" % vlan
|
||||
net.save()
|
||||
return net
|
||||
|
||||
def range(self):
|
||||
for idx in range(3, len(self.network)-2):
|
||||
yield self.network[idx]
|
||||
def __init__(self, network_id, network_str=None):
|
||||
super(BaseNetwork, self).__init__(object_id=network_id)
|
||||
self['network_id'] = network_id
|
||||
self['network_str'] = network_str
|
||||
self.save()
|
||||
|
||||
@property
|
||||
def network(self):
|
||||
return IPy.IP(self['network_str'])
|
||||
@property
|
||||
def netmask(self):
|
||||
return self.network.netmask()
|
||||
@property
|
||||
def broadcast(self):
|
||||
return self.network.broadcast()
|
||||
@property
|
||||
def bridge_name(self):
|
||||
return "br%s" % (self["vlan"])
|
||||
|
||||
@property
|
||||
def user(self):
|
||||
return users.UserManager.instance().get_user(self['user_id'])
|
||||
|
||||
@property
|
||||
def project(self):
|
||||
return users.UserManager.instance().get_project(self['project_id'])
|
||||
|
||||
@property
|
||||
def _hosts_key(self):
|
||||
return "network:%s:hosts" % (self['network_str'])
|
||||
|
||||
@property
|
||||
def hosts(self):
|
||||
return datastore.Redis.instance().hgetall(self._hosts_key)
|
||||
|
||||
def _add_host(self, _user_id, _project_id, host, target):
|
||||
datastore.Redis.instance().hset(self._hosts_key, host, target)
|
||||
|
||||
def _rem_host(self, host):
|
||||
datastore.Redis.instance().hdel(self._hosts_key, host)
|
||||
|
||||
@property
|
||||
def assigned(self):
|
||||
return datastore.Redis.instance().hkeys(self._hosts_key)
|
||||
|
||||
@property
|
||||
def available(self):
|
||||
for idx in range(3, len(self.network) - 1):
|
||||
address = str(self.network[idx])
|
||||
if not address in self.hosts.keys():
|
||||
yield str(address)
|
||||
|
||||
def allocate_ip(self, user_id, project_id, mac):
|
||||
for ip in self.range():
|
||||
address = str(ip)
|
||||
if not address in self.hosts.keys():
|
||||
for address in self.available:
|
||||
logging.debug("Allocating IP %s to %s" % (address, project_id))
|
||||
self.hosts[address] = {
|
||||
"address" : address, "user_id": user_id, "project_id" : project_id, 'mac' : mac
|
||||
}
|
||||
self._add_host(user_id, project_id, address, mac)
|
||||
self.express(address=address)
|
||||
return address
|
||||
raise exception.NoMoreAddresses()
|
||||
|
||||
def deallocate_ip(self, ip_str):
|
||||
if not ip_str in self.hosts.keys():
|
||||
if not ip_str in self.assigned:
|
||||
raise exception.AddressNotAllocated()
|
||||
del self.hosts[ip_str]
|
||||
# TODO(joshua) SCRUB from the leases file somehow
|
||||
self._rem_host(ip_str)
|
||||
self.deexpress(address=ip_str)
|
||||
|
||||
def list_addresses(self):
|
||||
for address in self.hosts.values():
|
||||
for address in self.hosts:
|
||||
yield address
|
||||
|
||||
def express(self, address=None):
|
||||
pass
|
||||
|
||||
def deexpress(self, address=None):
|
||||
pass
|
||||
def express(self, address=None): pass
|
||||
def deexpress(self, address=None): pass
|
||||
|
||||
|
||||
class Vlan(Network):
|
||||
class BridgedNetwork(BaseNetwork):
|
||||
"""
|
||||
VLAN configuration, that when expressed creates the vlan
|
||||
|
||||
properties:
|
||||
|
||||
vlan - integer (example: 42)
|
||||
bridge_dev - string (example: eth0)
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Vlan, self).__init__(*args, **kwargs)
|
||||
self.bridge_dev = FLAGS.bridge_dev
|
||||
|
||||
def express(self, address=None):
|
||||
super(Vlan, self).express(address=address)
|
||||
try:
|
||||
logging.debug("Starting VLAN inteface for %s network" % (self.vlan))
|
||||
linux_net.vlan_create(self)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
class VirtNetwork(Vlan):
|
||||
"""
|
||||
Virtual Network that can export libvirt configuration or express itself to
|
||||
create a bridge (with or without an IP address/netmask/gateway)
|
||||
Virtual Network that can express itself to create a vlan and
|
||||
a bridge (with or without an IP address/netmask/gateway)
|
||||
|
||||
properties:
|
||||
bridge_name - string (example value: br42)
|
||||
vlan - integer (example value: 42)
|
||||
bridge_dev - string (example: eth0)
|
||||
bridge_gets_ip - boolean used during bridge creation
|
||||
|
||||
if bridge_gets_ip then network address for bridge uses the properties:
|
||||
@@ -181,333 +166,242 @@ class VirtNetwork(Vlan):
|
||||
netmask
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_network_for_project(cls, user_id, project_id, security_group):
|
||||
vlan = get_vlan_for_project(project_id)
|
||||
network_str = get_subnet_from_vlan(vlan)
|
||||
logging.debug("creating network on vlan %s with network string %s" % (vlan, network_str))
|
||||
return cls.create(user_id, project_id, security_group, vlan, network_str)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(VirtNetwork, self).__init__(*args, **kwargs)
|
||||
|
||||
def virtXML(self):
|
||||
""" generate XML for libvirt network """
|
||||
|
||||
libvirt_xml = open(FLAGS.net_libvirt_xml_template).read()
|
||||
xml_info = {'name' : self.name,
|
||||
'bridge_name' : self.bridge_name,
|
||||
'device' : "vlan%s" % (self.vlan),
|
||||
'gateway' : self.gateway,
|
||||
'netmask' : self.netmask,
|
||||
}
|
||||
libvirt_xml = libvirt_xml % xml_info
|
||||
return libvirt_xml
|
||||
super(BridgedNetwork, self).__init__(*args, **kwargs)
|
||||
self['bridge_dev'] = FLAGS.bridge_dev
|
||||
self.save()
|
||||
|
||||
def express(self, address=None):
|
||||
""" creates a bridge device on top of the Vlan """
|
||||
super(VirtNetwork, self).express(address=address)
|
||||
try:
|
||||
logging.debug("Starting Bridge inteface for %s network" % (self.vlan))
|
||||
super(BridgedNetwork, self).express(address=address)
|
||||
linux_net.vlan_create(self)
|
||||
linux_net.bridge_create(self)
|
||||
except:
|
||||
pass
|
||||
|
||||
class DHCPNetwork(VirtNetwork):
|
||||
class DHCPNetwork(BridgedNetwork):
|
||||
"""
|
||||
properties:
|
||||
dhcp_listen_address: the ip of the gateway / dhcp host
|
||||
dhcp_range_start: the first ip to give out
|
||||
dhcp_range_end: the last ip to give out
|
||||
"""
|
||||
bridge_gets_ip = True
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(DHCPNetwork, self).__init__(*args, **kwargs)
|
||||
logging.debug("Initing DHCPNetwork object...")
|
||||
self.bridge_gets_ip = True
|
||||
self.dhcp_listen_address = self.network[1]
|
||||
self.dhcp_range_start = self.network[3]
|
||||
self.dhcp_range_end = self.network[-2]
|
||||
self.dhcp_range_end = self.network[-(1 + FLAGS.cnt_vpn_clients)]
|
||||
try:
|
||||
os.makedirs(FLAGS.networks_path)
|
||||
except Exception, err:
|
||||
pass
|
||||
|
||||
def express(self, address=None):
|
||||
super(DHCPNetwork, self).express(address=address)
|
||||
if len(self.hosts.values()) > 0:
|
||||
logging.debug("Starting dnsmasq server for network with vlan %s" % self.vlan)
|
||||
if len(self.assigned) > 0:
|
||||
logging.debug("Starting dnsmasq server for network with vlan %s",
|
||||
self['vlan'])
|
||||
linux_net.start_dnsmasq(self)
|
||||
else:
|
||||
logging.debug("Not launching dnsmasq cause I don't think we have any hosts.")
|
||||
logging.debug("Not launching dnsmasq: no hosts.")
|
||||
|
||||
def deexpress(self, address=None):
|
||||
# if this is the last address, stop dns
|
||||
super(DHCPNetwork, self).deexpress(address=address)
|
||||
if len(self.hosts.values()) == 0:
|
||||
if len(self.assigned) == 0:
|
||||
linux_net.stop_dnsmasq(self)
|
||||
else:
|
||||
linux_net.start_dnsmasq(self)
|
||||
|
||||
class PrivateNetwork(DHCPNetwork):
|
||||
def __init__(self, **kwargs):
|
||||
super(PrivateNetwork, self).__init__(**kwargs)
|
||||
# self.express()
|
||||
class PublicAddress(datastore.RedisModel):
|
||||
object_type="address"
|
||||
|
||||
def to_dict(self):
|
||||
return {'vlan': self.vlan,
|
||||
'network': self.network_str,
|
||||
'hosts': self.hosts}
|
||||
def __init__(self, address):
|
||||
super(PublicAddress, self).__init__(address)
|
||||
|
||||
class PublicNetwork(Network):
|
||||
def __init__(self, network="192.168.216.0/24", **kwargs):
|
||||
super(PublicNetwork, self).__init__(network=network, **kwargs)
|
||||
@classmethod
|
||||
def create(cls, user_id, project_id, address):
|
||||
addr = cls(address=address)
|
||||
addr['address'] = address
|
||||
addr['user_id'] = user_id
|
||||
addr['project_id'] = project_id
|
||||
addr['instance_id'] = 'available'
|
||||
addr['private_ip'] = 'available'
|
||||
addr["create_time"] = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
|
||||
addr.save()
|
||||
return addr
|
||||
|
||||
DEFAULT_PORTS = [("tcp",80), ("tcp",22), ("udp",1194), ("tcp",443)]
|
||||
class PublicNetworkController(BaseNetwork):
|
||||
def __init__(self, *args, **kwargs):
|
||||
network_id = "public:default"
|
||||
super(PublicNetworkController, self).__init__(network_id, FLAGS.public_range)
|
||||
self['user_id'] = "public"
|
||||
self['project_id'] = "public"
|
||||
self["create_time"] = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
|
||||
self["vlan"] = FLAGS.public_vlan
|
||||
self.save()
|
||||
self.express()
|
||||
|
||||
def allocate_ip(self, user_id, project_id, mac):
|
||||
for ip in self.range():
|
||||
address = str(ip)
|
||||
@property
|
||||
def available(self):
|
||||
for idx in range(2, len(self.network)-1):
|
||||
address = str(self.network[idx])
|
||||
if not address in self.hosts.keys():
|
||||
logging.debug("Allocating IP %s to %s" % (address, project_id))
|
||||
self.hosts[address] = {
|
||||
"address" : address, "user_id": user_id, "project_id" : project_id, 'mac' : mac
|
||||
}
|
||||
self.express(address=address)
|
||||
return address
|
||||
raise exception.NoMoreAddresses()
|
||||
yield address
|
||||
|
||||
def deallocate_ip(self, ip_str):
|
||||
if not ip_str in self.hosts:
|
||||
raise exception.AddressNotAllocated()
|
||||
del self.hosts[ip_str]
|
||||
# TODO(joshua) SCRUB from the leases file somehow
|
||||
self.deexpress(address=ip_str)
|
||||
@property
|
||||
def host_objs(self):
|
||||
for address in self.assigned:
|
||||
yield PublicAddress(address)
|
||||
|
||||
def get_public_ip_for_instance(self, instance_id):
|
||||
# FIXME: this should be a lookup - iteration won't scale
|
||||
for address_record in self.host_objs:
|
||||
if address_record.get('instance_id', 'available') == instance_id:
|
||||
return address_record['address']
|
||||
|
||||
def get_host(self, host):
|
||||
if host in self.assigned:
|
||||
return PublicAddress(host)
|
||||
return None
|
||||
|
||||
def _add_host(self, user_id, project_id, host, _target):
|
||||
datastore.Redis.instance().hset(self._hosts_key, host, project_id)
|
||||
PublicAddress.create(user_id, project_id, host)
|
||||
|
||||
def _rem_host(self, host):
|
||||
PublicAddress(host).destroy()
|
||||
datastore.Redis.instance().hdel(self._hosts_key, host)
|
||||
|
||||
def associate_address(self, public_ip, private_ip, instance_id):
|
||||
if not public_ip in self.hosts:
|
||||
if not public_ip in self.assigned:
|
||||
raise exception.AddressNotAllocated()
|
||||
for addr in self.hosts.values():
|
||||
if addr.has_key('private_ip') and addr['private_ip'] == private_ip:
|
||||
# TODO(joshua): Keep an index going both ways
|
||||
for addr in self.host_objs:
|
||||
if addr.get('private_ip', None) == private_ip:
|
||||
raise exception.AddressAlreadyAssociated()
|
||||
if self.hosts[public_ip].has_key('private_ip'):
|
||||
addr = self.get_host(public_ip)
|
||||
if addr.get('private_ip', 'available') != 'available':
|
||||
raise exception.AddressAlreadyAssociated()
|
||||
self.hosts[public_ip]['private_ip'] = private_ip
|
||||
self.hosts[public_ip]['instance_id'] = instance_id
|
||||
addr['private_ip'] = private_ip
|
||||
addr['instance_id'] = instance_id
|
||||
addr.save()
|
||||
self.express(address=public_ip)
|
||||
|
||||
def disassociate_address(self, public_ip):
|
||||
if not public_ip in self.hosts:
|
||||
if not public_ip in self.assigned:
|
||||
raise exception.AddressNotAllocated()
|
||||
if not self.hosts[public_ip].has_key('private_ip'):
|
||||
addr = self.get_host(public_ip)
|
||||
if addr.get('private_ip', 'available') == 'available':
|
||||
raise exception.AddressNotAssociated()
|
||||
self.deexpress(public_ip)
|
||||
del self.hosts[public_ip]['private_ip']
|
||||
del self.hosts[public_ip]['instance_id']
|
||||
# TODO Express the removal
|
||||
|
||||
def deexpress(self, address):
|
||||
addr = self.hosts[address]
|
||||
public_ip = addr['address']
|
||||
private_ip = addr['private_ip']
|
||||
linux_net.remove_rule("PREROUTING -t nat -d %s -j DNAT --to %s" % (public_ip, private_ip))
|
||||
linux_net.remove_rule("POSTROUTING -t nat -s %s -j SNAT --to %s" % (private_ip, public_ip))
|
||||
linux_net.remove_rule("FORWARD -d %s -p icmp -j ACCEPT" % (private_ip))
|
||||
for (protocol, port) in [("tcp",80), ("tcp",22), ("udp",1194), ("tcp",443)]:
|
||||
linux_net.remove_rule("FORWARD -d %s -p %s --dport %s -j ACCEPT" % (private_ip, protocol, port))
|
||||
self.deexpress(address=public_ip)
|
||||
addr['private_ip'] = 'available'
|
||||
addr['instance_id'] = 'available'
|
||||
addr.save()
|
||||
|
||||
def express(self, address=None):
|
||||
logging.debug("Todo - need to create IPTables natting entries for this net.")
|
||||
addresses = self.hosts.values()
|
||||
addresses = self.host_objs
|
||||
if address:
|
||||
addresses = [self.hosts[address]]
|
||||
addresses = [self.get_host(address)]
|
||||
for addr in addresses:
|
||||
if not addr.has_key('private_ip'):
|
||||
if addr.get('private_ip','available') == 'available':
|
||||
continue
|
||||
public_ip = addr['address']
|
||||
private_ip = addr['private_ip']
|
||||
linux_net.bind_public_ip(public_ip, FLAGS.public_interface)
|
||||
linux_net.confirm_rule("PREROUTING -t nat -d %s -j DNAT --to %s" % (public_ip, private_ip))
|
||||
linux_net.confirm_rule("POSTROUTING -t nat -s %s -j SNAT --to %s" % (private_ip, public_ip))
|
||||
linux_net.confirm_rule("PREROUTING -t nat -d %s -j DNAT --to %s"
|
||||
% (public_ip, private_ip))
|
||||
linux_net.confirm_rule("POSTROUTING -t nat -s %s -j SNAT --to %s"
|
||||
% (private_ip, public_ip))
|
||||
# TODO: Get these from the secgroup datastore entries
|
||||
linux_net.confirm_rule("FORWARD -d %s -p icmp -j ACCEPT" % (private_ip))
|
||||
for (protocol, port) in [("tcp",80), ("tcp",22), ("udp",1194), ("tcp",443)]:
|
||||
linux_net.confirm_rule("FORWARD -d %s -p %s --dport %s -j ACCEPT" % (private_ip, protocol, port))
|
||||
linux_net.confirm_rule("FORWARD -d %s -p icmp -j ACCEPT"
|
||||
% (private_ip))
|
||||
for (protocol, port) in DEFAULT_PORTS:
|
||||
linux_net.confirm_rule("FORWARD -d %s -p %s --dport %s -j ACCEPT"
|
||||
% (private_ip, protocol, port))
|
||||
|
||||
def deexpress(self, address=None):
|
||||
addr = self.get_host(address)
|
||||
private_ip = addr['private_ip']
|
||||
linux_net.remove_rule("PREROUTING -t nat -d %s -j DNAT --to %s"
|
||||
% (address, private_ip))
|
||||
linux_net.remove_rule("POSTROUTING -t nat -s %s -j SNAT --to %s"
|
||||
% (private_ip, address))
|
||||
linux_net.remove_rule("FORWARD -d %s -p icmp -j ACCEPT"
|
||||
% (private_ip))
|
||||
for (protocol, port) in DEFAULT_PORTS:
|
||||
linux_net.remove_rule("FORWARD -d %s -p %s --dport %s -j ACCEPT"
|
||||
% (private_ip, protocol, port))
|
||||
|
||||
|
||||
class NetworkPool(object):
|
||||
# TODO - Allocations need to be system global
|
||||
VLANS_KEY = "vlans"
|
||||
def _add_vlan(project_id, vlan):
|
||||
datastore.Redis.instance().hset(VLANS_KEY, project_id, vlan)
|
||||
|
||||
def __init__(self):
|
||||
self.network = IPy.IP(FLAGS.private_range)
|
||||
netsize = FLAGS.network_size
|
||||
if not netsize in [4,8,16,32,64,128,256,512,1024]:
|
||||
raise exception.NotValidNetworkSize()
|
||||
self.netsize = netsize
|
||||
self.startvlan = FLAGS.vlan_start
|
||||
def _rem_vlan(project_id):
|
||||
datastore.Redis.instance().hdel(VLANS_KEY, project_id)
|
||||
|
||||
def get_from_vlan(self, vlan):
|
||||
start = (vlan-self.startvlan) * self.netsize
|
||||
net_str = "%s-%s" % (self.network[start], self.network[start + self.netsize - 1])
|
||||
logging.debug("Allocating %s" % net_str)
|
||||
return net_str
|
||||
def get_assigned_vlans():
|
||||
""" Returns a dictionary, with keys of project_id and values of vlan_id """
|
||||
return datastore.Redis.instance().hgetall(VLANS_KEY)
|
||||
|
||||
|
||||
class VlanPool(object):
|
||||
def __init__(self, **kwargs):
|
||||
self.start = FLAGS.vlan_start
|
||||
self.end = FLAGS.vlan_end
|
||||
self.vlans = kwargs.get('vlans', {})
|
||||
self.vlanpool = {}
|
||||
self.manager = users.UserManager.instance()
|
||||
for project_id, vlan in self.vlans.iteritems():
|
||||
self.vlanpool[vlan] = project_id
|
||||
|
||||
def to_dict(self):
|
||||
return {'vlans': self.vlans}
|
||||
|
||||
def __str__(self):
|
||||
return json.dumps(self.to_dict())
|
||||
|
||||
def __unicode__(self):
|
||||
return json.dumps(self.to_dict())
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, args):
|
||||
for arg in args.keys():
|
||||
value = args[arg]
|
||||
del args[arg]
|
||||
args[str(arg)] = value
|
||||
self = cls(**args)
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_string):
|
||||
parsed = json.loads(json_string)
|
||||
return cls.from_dict(parsed)
|
||||
|
||||
def assign_vlan(self, project_id, vlan):
|
||||
logging.debug("Assigning vlan %s to project %s" % (vlan, project_id))
|
||||
self.vlans[project_id] = vlan
|
||||
self.vlanpool[vlan] = project_id
|
||||
return self.vlans[project_id]
|
||||
|
||||
def next(self, project_id):
|
||||
for old_project_id, vlan in self.vlans.iteritems():
|
||||
if not self.manager.get_project(old_project_id):
|
||||
_get_keeper()["%s-default" % old_project_id] = {}
|
||||
del _get_keeper()["%s-default" % old_project_id]
|
||||
del self.vlans[old_project_id]
|
||||
return self.assign_vlan(project_id, vlan)
|
||||
vlans = self.vlanpool.keys()
|
||||
vlans.append(self.start)
|
||||
nextvlan = max(vlans) + 1
|
||||
if nextvlan == self.end:
|
||||
def get_vlan_for_project(project_id):
|
||||
"""
|
||||
Allocate vlan IDs to individual users.
|
||||
"""
|
||||
vlan = datastore.Redis.instance().hget(VLANS_KEY, project_id)
|
||||
if vlan:
|
||||
return vlan
|
||||
assigned_vlans = get_assigned_vlans()
|
||||
# TODO(joshua) I can do this in one loop, I think
|
||||
for old_project_id, vlan in assigned_vlans.iteritems():
|
||||
if not users.UserManager.instance().get_project(old_project_id):
|
||||
_rem_vlan(old_project_id)
|
||||
_add_vlan(project_id, vlan)
|
||||
return vlan
|
||||
for vlan in range(FLAGS.vlan_start, FLAGS.vlan_end):
|
||||
if not str(vlan) in assigned_vlans.values():
|
||||
_add_vlan(project_id, vlan)
|
||||
return vlan
|
||||
raise exception.AddressNotAllocated("Out of VLANs")
|
||||
return self.assign_vlan(project_id, nextvlan)
|
||||
|
||||
|
||||
class NetworkController(object):
|
||||
""" The network controller is in charge of network connections """
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
logging.debug("Starting up the network controller.")
|
||||
self.manager = users.UserManager.instance()
|
||||
self._pubnet = None
|
||||
if not _get_keeper()['vlans']:
|
||||
_get_keeper()['vlans'] = {}
|
||||
if not _get_keeper()['public']:
|
||||
_get_keeper()['public'] = {'vlan': FLAGS.public_vlan, 'network' : FLAGS.public_range}
|
||||
self.express()
|
||||
|
||||
def reset(self):
|
||||
_get_keeper()['public'] = {'vlan': FLAGS.public_vlan, 'network': FLAGS.public_range }
|
||||
_get_keeper()['vlans'] = {}
|
||||
# TODO : Get rid of old interfaces, bridges, and IPTables rules.
|
||||
|
||||
@property
|
||||
def public_net(self):
|
||||
if not self._pubnet:
|
||||
self._pubnet = PublicNetwork.from_dict(_get_keeper()['public'])
|
||||
self._pubnet.load(**_get_keeper()['public'])
|
||||
return self._pubnet
|
||||
|
||||
@property
|
||||
def vlan_pool(self):
|
||||
return VlanPool.from_dict(_get_keeper()['vlans'])
|
||||
|
||||
def get_network_from_name(self, network_name):
|
||||
net_dict = _get_keeper()[network_name]
|
||||
if net_dict:
|
||||
return PrivateNetwork.from_dict(net_dict)
|
||||
return None
|
||||
|
||||
def get_public_ip_for_instance(self, instance_id):
|
||||
# FIXME: this should be a lookup - iteration won't scale
|
||||
for address_record in self.describe_addresses(type=PublicNetwork):
|
||||
if address_record.get(u'instance_id', 'free') == instance_id:
|
||||
return address_record[u'address']
|
||||
|
||||
def get_project_network(self, project_id):
|
||||
""" get a project's private network, allocating one if needed """
|
||||
|
||||
project = self.manager.get_project(project_id)
|
||||
if not project:
|
||||
raise Exception("Project %s doesn't exist, uhoh." % project_id)
|
||||
project_net = self.get_network_from_name("%s-default" % project_id)
|
||||
if not project_net:
|
||||
pool = self.vlan_pool
|
||||
vlan = pool.next(project_id)
|
||||
private_pool = NetworkPool()
|
||||
network_str = private_pool.get_from_vlan(vlan)
|
||||
logging.debug("Constructing network %s and %s for %s" % (network_str, vlan, project_id))
|
||||
project_net = PrivateNetwork(
|
||||
network=network_str,
|
||||
vlan=vlan)
|
||||
_get_keeper()["%s-default" % project_id] = project_net.to_dict()
|
||||
_get_keeper()['vlans'] = pool.to_dict()
|
||||
return project_net
|
||||
|
||||
def allocate_address(self, user_id, project_id, mac=None, type=PrivateNetwork):
|
||||
ip = None
|
||||
net_name = None
|
||||
if type == PrivateNetwork:
|
||||
net = self.get_project_network(project_id)
|
||||
ip = net.allocate_ip(user_id, project_id, mac)
|
||||
net_name = net.name
|
||||
_get_keeper()["%s-default" % project_id] = net.to_dict()
|
||||
else:
|
||||
net = self.public_net
|
||||
ip = net.allocate_ip(user_id, project_id, mac)
|
||||
net_name = net.name
|
||||
_get_keeper()['public'] = net.to_dict()
|
||||
return (ip, net_name)
|
||||
|
||||
def deallocate_address(self, address):
|
||||
if address in self.public_net.network:
|
||||
net = self.public_net
|
||||
rv = net.deallocate_ip(str(address))
|
||||
_get_keeper()['public'] = net.to_dict()
|
||||
return rv
|
||||
for project in self.manager.get_projects():
|
||||
if address in self.get_project_network(project.id).network:
|
||||
net = self.get_project_network(project.id)
|
||||
rv = net.deallocate_ip(str(address))
|
||||
_get_keeper()["%s-default" % project.id] = net.to_dict()
|
||||
return rv
|
||||
def get_network_by_address(address):
|
||||
for project in users.UserManager.instance().get_projects():
|
||||
net = get_project_network(project.id)
|
||||
if address in net.assigned:
|
||||
return net
|
||||
raise exception.AddressNotAllocated()
|
||||
|
||||
def describe_addresses(self, type=PrivateNetwork):
|
||||
if type == PrivateNetwork:
|
||||
addresses = []
|
||||
for project in self.manager.get_projects():
|
||||
addresses.extend(self.get_project_network(project.id).list_addresses())
|
||||
return addresses
|
||||
return self.public_net.list_addresses()
|
||||
def allocate_ip(user_id, project_id, mac):
|
||||
return get_project_network(project_id).allocate_ip(user_id, project_id, mac)
|
||||
|
||||
def associate_address(self, address, private_ip, instance_id):
|
||||
net = self.public_net
|
||||
rv = net.associate_address(address, private_ip, instance_id)
|
||||
_get_keeper()['public'] = net.to_dict()
|
||||
return rv
|
||||
def deallocate_ip(address):
|
||||
return get_network_by_address(address).deallocate_ip(address)
|
||||
|
||||
def disassociate_address(self, address):
|
||||
net = self.public_net
|
||||
rv = net.disassociate_address(address)
|
||||
_get_keeper()['public'] = net.to_dict()
|
||||
return rv
|
||||
def get_project_network(project_id, security_group='default'):
|
||||
""" get a project's private network, allocating one if needed """
|
||||
project = users.UserManager.instance().get_project(project_id)
|
||||
if not project:
|
||||
raise nova.exception.Error("Project %s doesn't exist, uhoh." % project_id)
|
||||
return DHCPNetwork.get_network_for_project(project.project_manager_id, project.id, security_group)
|
||||
|
||||
def express(self,address=None):
|
||||
for project in self.manager.get_projects():
|
||||
self.get_project_network(project.id).express()
|
||||
|
||||
def report_state(self):
|
||||
pass
|
||||
def get_subnet_from_vlan(vlan):
|
||||
"""Assign one subnet to each VLAN, for now."""
|
||||
vlan = int(vlan)
|
||||
network = IPy.IP(FLAGS.private_range)
|
||||
start = (vlan-FLAGS.vlan_start) * FLAGS.network_size
|
||||
return "%s-%s" % (network[start], network[start + FLAGS.network_size - 1])
|
||||
|
||||
def restart_nets():
|
||||
""" Ensure the network for each user is enabled"""
|
||||
for project in users.UserManager.instance().get_projects():
|
||||
get_project_network(project.id).express()
|
||||
|
||||
@@ -137,11 +137,15 @@ class Node(object, service.Service):
|
||||
logging.debug("Reporting State")
|
||||
return
|
||||
|
||||
@exception.wrap_exception
|
||||
# @exception.wrap_exception
|
||||
def run_instance(self, instance_id, **_kwargs):
|
||||
""" launch a new instance with specified options """
|
||||
logging.debug("Starting instance %s..." % (instance_id))
|
||||
inst = self.instdir.get(instance_id)
|
||||
# TODO: Get the real security group of launch in here
|
||||
security_group = "default"
|
||||
net = network.BridgedNetwork.get_network_for_project(inst['user_id'], inst['project_id'],
|
||||
security_group).express()
|
||||
inst['node_name'] = FLAGS.node_name
|
||||
inst.save()
|
||||
# TODO(vish) check to make sure the availability zone matches
|
||||
@@ -337,8 +341,6 @@ class Instance(object):
|
||||
'basepath', os.path.abspath(
|
||||
os.path.join(FLAGS.instances_path, self.name)))
|
||||
self._s['memory_kb'] = int(self._s['memory_mb']) * 1024
|
||||
# TODO(joshua) - Get this from network directory controller later
|
||||
self._s['bridge_name'] = data.get('bridge_name', 'br0')
|
||||
self._s['image_id'] = data.get('image_id', FLAGS.default_image)
|
||||
self._s['kernel_id'] = data.get('kernel_id', FLAGS.default_kernel)
|
||||
self._s['ramdisk_id'] = data.get('ramdisk_id', FLAGS.default_ramdisk)
|
||||
@@ -360,6 +362,7 @@ class Instance(object):
|
||||
self._s['addressing_type'] = data.get('addressing_type', None)
|
||||
self._s['availability_zone'] = data.get('availability_zone', 'fixme')
|
||||
|
||||
self._s['bridge_name'] = data.get('bridge_name', None)
|
||||
#TODO: put real dns items here
|
||||
self._s['private_dns_name'] = data.get('private_dns_name', 'fixme')
|
||||
self._s['dns_name'] = data.get('dns_name',
|
||||
@@ -476,7 +479,7 @@ class Instance(object):
|
||||
logging.debug('rebooted instance %s' % self.name)
|
||||
defer.returnValue(None)
|
||||
|
||||
@exception.wrap_exception
|
||||
# @exception.wrap_exception
|
||||
def spawn(self):
|
||||
self.datamodel['state'] = "spawning"
|
||||
self.datamodel.save()
|
||||
@@ -516,30 +519,3 @@ class Instance(object):
|
||||
else:
|
||||
console = 'FAKE CONSOLE OUTPUT'
|
||||
return defer.succeed(console)
|
||||
|
||||
def generate_mac(self):
|
||||
mac = [0x00, 0x16, 0x3e, random.randint(0x00, 0x7f),
|
||||
random.randint(0x00, 0xff), random.randint(0x00, 0xff)
|
||||
]
|
||||
return ':'.join(map(lambda x: "%02x" % x, mac))
|
||||
|
||||
|
||||
|
||||
class NetworkNode(Node):
|
||||
def __init__(self, **kwargs):
|
||||
super(NetworkNode, self).__init__(**kwargs)
|
||||
self.virtNets = {}
|
||||
|
||||
def add_network(self, net_dict):
|
||||
net = network.VirtNetwork(**net_dict)
|
||||
self.virtNets[net.name] = net
|
||||
self.virtNets[net.name].express()
|
||||
return defer.succeed({'retval': 'network added'})
|
||||
|
||||
@exception.wrap_exception
|
||||
def run_instance(self, instance_id, **kwargs):
|
||||
inst = self.instdir.get(instance_id)
|
||||
net_dict = json.loads(inst.get('network_str', "{}"))
|
||||
self.add_network(net_dict)
|
||||
return super(NetworkNode, self).run_instance(instance_id, **kwargs)
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import json
|
||||
import logging
|
||||
import os
|
||||
import sqlite3
|
||||
import time
|
||||
|
||||
from nova import vendor
|
||||
import redis
|
||||
@@ -77,10 +78,11 @@ class RedisModel(object):
|
||||
def set_default_state(self):
|
||||
self.state = {'state' : 'pending'}
|
||||
self.state[self.object_type+"_id"] = self.object_id
|
||||
self.state["create_time"] = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
|
||||
|
||||
@property
|
||||
def __redis_key(self):
|
||||
""" Magic string for instance keys """
|
||||
""" Magic string for keys """
|
||||
return '%s:%s' % (self.object_type, self.object_id)
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
@@ -60,7 +60,7 @@ class CloudController(object):
|
||||
"""
|
||||
def __init__(self):
|
||||
self.instdir = model.InstanceDirectory()
|
||||
self.network = network.NetworkController()
|
||||
self.network = network.PublicNetworkController()
|
||||
self.setup()
|
||||
|
||||
@property
|
||||
@@ -254,21 +254,10 @@ class CloudController(object):
|
||||
res.addCallback(_format_result)
|
||||
return res
|
||||
|
||||
def _convert_address(self, network_address):
|
||||
# FIXME(vish): this should go away when network.py stores info properly
|
||||
address = {}
|
||||
address['public_ip'] == network_address[u'address']
|
||||
address['user_id'] == network_address[u'user_id']
|
||||
address['project_id'] == network_address.get(u'project_id', address['user_id'])
|
||||
address['instance_id'] == network_address.get(u'instance_id', None)
|
||||
return address
|
||||
|
||||
def _get_address(self, context, public_ip):
|
||||
# right now all addresses are allocated locally
|
||||
# FIXME(vish) this should move into network.py
|
||||
for network_address in self.network.describe_addresses():
|
||||
if network_address[u'address'] == public_ip:
|
||||
address = self._convert_address(network_address)
|
||||
for address in self.network.hosts:
|
||||
if address['address'] == public_ip:
|
||||
if context.user.is_admin() or address['project_id'] == context.project.id:
|
||||
return address
|
||||
raise exception.NotFound("Address at ip %s not found" % public_ip)
|
||||
@@ -398,14 +387,12 @@ class CloudController(object):
|
||||
def format_addresses(self, context):
|
||||
addresses = []
|
||||
# TODO(vish): move authorization checking into network.py
|
||||
for network_address in self.network.describe_addresses(type=network.PublicNetwork):
|
||||
for address in self.network.hosts:
|
||||
#logging.debug(address_record)
|
||||
address = self._convert_address(network_address)
|
||||
address_rv = {
|
||||
'public_ip': address['public_ip'],
|
||||
'public_ip': address['address'],
|
||||
'instance_id' : address.get('instance_id', 'free')
|
||||
}
|
||||
# FIXME: add another field for user id
|
||||
if context.user.is_admin():
|
||||
address_rv['instance_id'] = "%s (%s, %s)" % (
|
||||
address['instance_id'],
|
||||
@@ -417,17 +404,17 @@ class CloudController(object):
|
||||
return {'addressesSet': addresses}
|
||||
|
||||
def allocate_address(self, context, **kwargs):
|
||||
(address,network_name) = self.network.allocate_address(
|
||||
context.user.id, context.project_id, type=network.PublicNetwork)
|
||||
address = self.network.allocate_ip(
|
||||
context.user.id, context.project.id, 'public')
|
||||
return defer.succeed({'addressSet': [{'publicIp' : address}]})
|
||||
|
||||
def release_address(self, context, public_ip, **kwargs):
|
||||
address = self._get_address(public_ip)
|
||||
self.network.deallocate_ip(public_ip)
|
||||
return defer.succeed({'releaseResponse': ["Address released."]})
|
||||
|
||||
def associate_address(self, context, instance_id, **kwargs):
|
||||
instance = self._get_instance(context, instance_id)
|
||||
rv = self.network.associate_address(
|
||||
self.network.associate_address(
|
||||
kwargs['public_ip'],
|
||||
instance['private_dns_name'],
|
||||
instance_id)
|
||||
@@ -435,7 +422,7 @@ class CloudController(object):
|
||||
|
||||
def disassociate_address(self, context, public_ip, **kwargs):
|
||||
address = self._get_address(public_ip)
|
||||
rv = self.network.disassociate_address(public_ip)
|
||||
self.network.disassociate_address(public_ip)
|
||||
# TODO - Strip the IP from the instance
|
||||
return defer.succeed({'disassociateResponse': ["Address disassociated."]})
|
||||
|
||||
@@ -466,14 +453,10 @@ class CloudController(object):
|
||||
inst['project_id'] = context.project.id
|
||||
inst['mac_address'] = utils.generate_mac()
|
||||
inst['ami_launch_index'] = num
|
||||
address, _netname = self.network.allocate_address(
|
||||
user_id=inst['user_id'],
|
||||
project_id=inst['project_id'],
|
||||
mac=inst['mac_address'])
|
||||
network = self.network.get_users_network(str(context.user.id))
|
||||
inst['network_str'] = json.dumps(network.to_dict())
|
||||
inst['bridge_name'] = network.bridge_name
|
||||
address = network.allocate_ip(
|
||||
inst['user_id'], inst['project_id'], mac=inst['mac_address'])
|
||||
inst['private_dns_name'] = str(address)
|
||||
inst['bridge_name'] = network.BridgedNetwork.get_network_for_project(inst['user_id'], inst['project_id'])['bridge_name']
|
||||
# TODO: allocate expresses on the router node
|
||||
inst.save()
|
||||
rpc.cast(FLAGS.compute_topic,
|
||||
@@ -502,7 +485,7 @@ class CloudController(object):
|
||||
if instance.get('private_dns_name', None):
|
||||
logging.debug("Deallocating address %s" % instance.get('private_dns_name', None))
|
||||
try:
|
||||
self.network.deallocate_address(instance.get('private_dns_name', None))
|
||||
self.network.deallocate_ip(instance.get('private_dns_name', None))
|
||||
except Exception, _err:
|
||||
pass
|
||||
if instance.get('node_name', 'unassigned') != 'unassigned': #It's also internal default
|
||||
|
||||
@@ -23,11 +23,17 @@ from nova import flags
|
||||
from nova import test
|
||||
from nova.compute import network
|
||||
from nova.auth import users
|
||||
from nova import utils
|
||||
|
||||
|
||||
class NetworkTestCase(test.TrialTestCase):
|
||||
def setUp(self):
|
||||
super(NetworkTestCase, self).setUp()
|
||||
self.flags(fake_libvirt=True,
|
||||
fake_storage=True,
|
||||
fake_network=True,
|
||||
network_size=32,
|
||||
redis_db=8)
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
self.manager = users.UserManager.instance()
|
||||
try:
|
||||
@@ -37,7 +43,7 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
name = 'project%s' % i
|
||||
if not self.manager.get_project(name):
|
||||
self.manager.create_project(name, 'netuser', name)
|
||||
self.network = network.NetworkController(netsize=16)
|
||||
self.network = network.PublicNetworkController()
|
||||
|
||||
def tearDown(self):
|
||||
super(NetworkTestCase, self).tearDown()
|
||||
@@ -46,70 +52,69 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
self.manager.delete_project(name)
|
||||
self.manager.delete_user('netuser')
|
||||
|
||||
def test_network_serialization(self):
|
||||
net1 = network.Network(vlan=100, network="192.168.100.0/24", conn=None)
|
||||
address = net1.allocate_ip("netuser", "project0", "01:24:55:36:f2:a0")
|
||||
net_json = str(net1)
|
||||
net2 = network.Network.from_json(net_json)
|
||||
self.assertEqual(net_json, str(net2))
|
||||
self.assertTrue(IPy.IP(address) in net2.network)
|
||||
def test_public_network_allocation(self):
|
||||
pubnet = IPy.IP(flags.FLAGS.public_range)
|
||||
address = self.network.allocate_ip("netuser", "project0", "public")
|
||||
self.assertTrue(IPy.IP(address) in pubnet)
|
||||
self.assertTrue(IPy.IP(address) in self.network.network)
|
||||
|
||||
def test_allocate_deallocate_address(self):
|
||||
(address, net_name) = self.network.allocate_address("netuser",
|
||||
"project0", "01:24:55:36:f2:a0")
|
||||
def test_allocate_deallocate_ip(self):
|
||||
address = network.allocate_ip(
|
||||
"netuser", "project0", utils.generate_mac())
|
||||
logging.debug("Was allocated %s" % (address))
|
||||
self.assertEqual(True, address in self._get_project_addresses("project0"))
|
||||
rv = self.network.deallocate_address(address)
|
||||
rv = network.deallocate_ip(address)
|
||||
self.assertEqual(False, address in self._get_project_addresses("project0"))
|
||||
|
||||
def test_range_allocation(self):
|
||||
(address, net_name) = self.network.allocate_address("netuser",
|
||||
"project0", "01:24:55:36:f2:a0")
|
||||
(secondaddress, net_name) = self.network.allocate_address("netuser",
|
||||
"project1", "01:24:55:36:f2:a0")
|
||||
self.assertEqual(True, address in self._get_project_addresses("project0"))
|
||||
address = network.allocate_ip(
|
||||
"netuser", "project0", utils.generate_mac())
|
||||
secondaddress = network.allocate_ip(
|
||||
"netuser", "project1", utils.generate_mac())
|
||||
self.assertEqual(True,
|
||||
address in self._get_project_addresses("project0"))
|
||||
self.assertEqual(True,
|
||||
secondaddress in self._get_project_addresses("project1"))
|
||||
self.assertEqual(False, address in self._get_project_addresses("project1"))
|
||||
rv = self.network.deallocate_address(address)
|
||||
rv = network.deallocate_ip(address)
|
||||
self.assertEqual(False, address in self._get_project_addresses("project0"))
|
||||
rv = self.network.deallocate_address(secondaddress)
|
||||
rv = network.deallocate_ip(secondaddress)
|
||||
self.assertEqual(False,
|
||||
secondaddress in self._get_project_addresses("project1"))
|
||||
|
||||
def test_subnet_edge(self):
|
||||
(secondaddress, net_name) = self.network.allocate_address("netuser", "project0")
|
||||
secondaddress = network.allocate_ip("netuser", "project0",
|
||||
utils.generate_mac())
|
||||
for project in range(1,5):
|
||||
project_id = "project%s" % (project)
|
||||
(address, net_name) = self.network.allocate_address("netuser",
|
||||
project_id, "01:24:55:36:f2:a0")
|
||||
(address2, net_name) = self.network.allocate_address("netuser",
|
||||
project_id, "01:24:55:36:f2:a0")
|
||||
(address3, net_name) = self.network.allocate_address("netuser",
|
||||
project_id, "01:24:55:36:f2:a0")
|
||||
address = network.allocate_ip(
|
||||
"netuser", project_id, utils.generate_mac())
|
||||
address2 = network.allocate_ip(
|
||||
"netuser", project_id, utils.generate_mac())
|
||||
address3 = network.allocate_ip(
|
||||
"netuser", project_id, utils.generate_mac())
|
||||
self.assertEqual(False,
|
||||
address in self._get_project_addresses("project0"))
|
||||
self.assertEqual(False,
|
||||
address2 in self._get_project_addresses("project0"))
|
||||
self.assertEqual(False,
|
||||
address3 in self._get_project_addresses("project0"))
|
||||
rv = self.network.deallocate_address(address)
|
||||
rv = self.network.deallocate_address(address2)
|
||||
rv = self.network.deallocate_address(address3)
|
||||
rv = self.network.deallocate_address(secondaddress)
|
||||
rv = network.deallocate_ip(address)
|
||||
rv = network.deallocate_ip(address2)
|
||||
rv = network.deallocate_ip(address3)
|
||||
rv = network.deallocate_ip(secondaddress)
|
||||
|
||||
def test_too_many_projects(self):
|
||||
for i in range(0, 30):
|
||||
name = 'toomany-project%s' % i
|
||||
self.manager.create_project(name, 'netuser', name)
|
||||
(address, net_name) = self.network.allocate_address("netuser",
|
||||
name, "01:24:55:36:f2:a0")
|
||||
address = network.allocate_ip(
|
||||
"netuser", name, utils.generate_mac())
|
||||
rv = network.deallocate_ip(address)
|
||||
self.manager.delete_project(name)
|
||||
|
||||
def _get_project_addresses(self, project_id):
|
||||
rv = self.network.describe_addresses()
|
||||
project_addresses = []
|
||||
for item in rv:
|
||||
if item['project_id'] == project_id:
|
||||
project_addresses.append(item['address'])
|
||||
for addr in network.get_project_network(project_id).list_addresses():
|
||||
project_addresses.append(addr)
|
||||
return project_addresses
|
||||
|
||||
Reference in New Issue
Block a user