Huge network refactor, Round I
Made network into its own binary Made simple network a plugabble class Fixed unittests Moved various classes around Moved mac generation into network class
This commit is contained in:
@@ -35,32 +35,34 @@ sys.path.append(os.path.abspath(os.path.join(__file__, "../../")))
|
||||
from nova import flags
|
||||
from nova import rpc
|
||||
from nova import utils
|
||||
from nova.compute import linux_net
|
||||
from nova.compute import network
|
||||
|
||||
from nova.network import linux_net
|
||||
from nova.network import model
|
||||
from nova.network import service
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
|
||||
def add_lease(mac, ip, hostname, interface):
|
||||
if FLAGS.fake_rabbit:
|
||||
network.lease_ip(ip)
|
||||
service.VlanNetworkService().lease_ip(ip)
|
||||
else:
|
||||
rpc.cast(FLAGS.cloud_topic, {"method": "lease_ip",
|
||||
"args" : {"address": ip}})
|
||||
rpc.cast("%s.%s" (FLAGS.network_topic, FLAGS.node_name),
|
||||
{"method": "lease_ip",
|
||||
"args" : {"fixed_ip": ip}})
|
||||
|
||||
def old_lease(mac, ip, hostname, interface):
|
||||
logging.debug("Adopted old lease or got a change of mac/hostname")
|
||||
|
||||
def del_lease(mac, ip, hostname, interface):
|
||||
if FLAGS.fake_rabbit:
|
||||
network.release_ip(ip)
|
||||
service.VlanNetworkService().release_ip(ip)
|
||||
else:
|
||||
rpc.cast(FLAGS.cloud_topic, {"method": "release_ip",
|
||||
"args" : {"address": ip}})
|
||||
rpc.cast("%s.%s" (FLAGS.network_topic, FLAGS.node_name),
|
||||
{"method": "release_ip",
|
||||
"args" : {"fixed_ip": ip}})
|
||||
|
||||
def init_leases(interface):
|
||||
net = network.get_network_by_interface(interface)
|
||||
net = model.get_network_by_interface(interface)
|
||||
res = ""
|
||||
for host_name in net.hosts:
|
||||
res += "%s\n" % linux_net.hostDHCP(net, host_name, net.hosts[host_name])
|
||||
|
||||
@@ -21,12 +21,19 @@
|
||||
Twistd daemon for the nova network nodes.
|
||||
"""
|
||||
|
||||
from nova import flags
|
||||
from nova import twistd
|
||||
from nova.network import service
|
||||
from nova import utils
|
||||
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
flags.DEFINE_string('network_service',
|
||||
'nova.network.service.VlanNetworkService',
|
||||
'Service Class for Networking')
|
||||
|
||||
if __name__ == '__main__':
|
||||
twistd.serve(__file__)
|
||||
|
||||
if __name__ == '__builtin__':
|
||||
application = service.NetworkService.create()
|
||||
application = utils.import_class(FLAGS.network_service).create()
|
||||
|
||||
@@ -36,11 +36,9 @@ from nova import utils
|
||||
from nova.auth import rbac
|
||||
from nova.auth import manager
|
||||
from nova.compute import model
|
||||
from nova.compute import network
|
||||
from nova.compute.instance_types import INSTANCE_TYPES
|
||||
from nova.compute import service as compute_service
|
||||
from nova.endpoint import images
|
||||
from nova.volume import service as volume_service
|
||||
from nova.volume import service
|
||||
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
@@ -64,7 +62,6 @@ class CloudController(object):
|
||||
"""
|
||||
def __init__(self):
|
||||
self.instdir = model.InstanceDirectory()
|
||||
self.network = network.PublicNetworkController()
|
||||
self.setup()
|
||||
|
||||
@property
|
||||
@@ -76,7 +73,7 @@ class CloudController(object):
|
||||
def volumes(self):
|
||||
""" returns a list of all volumes """
|
||||
for volume_id in datastore.Redis.instance().smembers("volumes"):
|
||||
volume = volume_service.get_volume(volume_id)
|
||||
volume = service.get_volume(volume_id)
|
||||
yield volume
|
||||
|
||||
def __str__(self):
|
||||
@@ -222,7 +219,7 @@ class CloudController(object):
|
||||
callback=_complete)
|
||||
return d
|
||||
|
||||
except users.UserError, e:
|
||||
except manager.UserError as e:
|
||||
raise
|
||||
|
||||
@rbac.allow('all')
|
||||
@@ -331,7 +328,7 @@ class CloudController(object):
|
||||
raise exception.NotFound('Instance %s could not be found' % instance_id)
|
||||
|
||||
def _get_volume(self, context, volume_id):
|
||||
volume = volume_service.get_volume(volume_id)
|
||||
volume = service.get_volume(volume_id)
|
||||
if context.user.is_admin() or volume['project_id'] == context.project.id:
|
||||
return volume
|
||||
raise exception.NotFound('Volume %s could not be found' % volume_id)
|
||||
@@ -472,29 +469,34 @@ class CloudController(object):
|
||||
|
||||
@rbac.allow('netadmin')
|
||||
def allocate_address(self, context, **kwargs):
|
||||
address = self.network.allocate_ip(
|
||||
context.user.id, context.project.id, 'public')
|
||||
return defer.succeed({'addressSet': [{'publicIp' : address}]})
|
||||
alloc_result = rpc.call(self._get_network_host(context),
|
||||
{"method": "allocate_elastic_ip"})
|
||||
public_ip = alloc_result['result']
|
||||
return defer.succeed({'addressSet': [{'publicIp' : public_ip}]})
|
||||
|
||||
@rbac.allow('netadmin')
|
||||
def release_address(self, context, public_ip, **kwargs):
|
||||
self.network.deallocate_ip(public_ip)
|
||||
# NOTE(vish): Should we make sure this works?
|
||||
rpc.cast(self._get_network_host(context),
|
||||
{"method": "deallocate_elastic_ip",
|
||||
"args": {"elastic_ip": public_ip}})
|
||||
return defer.succeed({'releaseResponse': ["Address released."]})
|
||||
|
||||
@rbac.allow('netadmin')
|
||||
def associate_address(self, context, instance_id, **kwargs):
|
||||
def associate_address(self, context, instance_id, public_ip, **kwargs):
|
||||
instance = self._get_instance(context, instance_id)
|
||||
self.network.associate_address(
|
||||
kwargs['public_ip'],
|
||||
instance['private_dns_name'],
|
||||
instance_id)
|
||||
address = self._get_address(context, public_ip)
|
||||
rpc.cast(self._get_network_host(context),
|
||||
{"method": "associate_elastic_ip",
|
||||
"args": {"elastic_ip": address['public_ip'],
|
||||
"fixed_ip": instance['private_dns_name'],
|
||||
"instance_id": instance['instance_id']}})
|
||||
return defer.succeed({'associateResponse': ["Address associated."]})
|
||||
|
||||
@rbac.allow('netadmin')
|
||||
def disassociate_address(self, context, public_ip, **kwargs):
|
||||
address = self._get_address(context, public_ip)
|
||||
self.network.disassociate_address(public_ip)
|
||||
# TODO - Strip the IP from the instance
|
||||
return defer.succeed({'disassociateResponse': ["Address disassociated."]})
|
||||
|
||||
def release_ip(self, context, private_ip, **kwargs):
|
||||
@@ -505,7 +507,13 @@ class CloudController(object):
|
||||
self.network.lease_ip(private_ip)
|
||||
return defer.succeed({'leaseResponse': ["Address leased."]})
|
||||
|
||||
def get_network_host(self, context):
|
||||
# FIXME(vish): this is temporary until we store net hosts for project
|
||||
import socket
|
||||
return socket.gethostname()
|
||||
|
||||
@rbac.allow('projectmanager', 'sysadmin')
|
||||
@defer.inlineCallbacks
|
||||
def run_instances(self, context, **kwargs):
|
||||
# make sure user can access the image
|
||||
# vpn image is private so it doesn't show up on lists
|
||||
@@ -539,14 +547,25 @@ class CloudController(object):
|
||||
key_data = key_pair.public_key
|
||||
# TODO: Get the real security group of launch in here
|
||||
security_group = "default"
|
||||
if FLAGS.simple_network:
|
||||
bridge_name = FLAGS.simple_network_bridge
|
||||
else:
|
||||
net = network.BridgedNetwork.get_network_for_project(
|
||||
context.user.id, context.project.id, security_group)
|
||||
bridge_name = net['bridge_name']
|
||||
create_result = yield rpc.call(FLAGS.network_topic,
|
||||
{"method": "create_network",
|
||||
"args": {"user_id": context.user.id,
|
||||
"project_id": context.project.id,
|
||||
"security_group": security_group}})
|
||||
bridge_name = create_result['result']
|
||||
net_host = self._get_network_host(context)
|
||||
for num in range(int(kwargs['max_count'])):
|
||||
vpn = False
|
||||
if image_id == FLAGS.vpn_image_id:
|
||||
vpn = True
|
||||
allocate_result = yield rpc.call(net_host,
|
||||
{"method": "allocate_fixed_ip",
|
||||
"args": {"user_id": context.user.id,
|
||||
"project_id": context.project.id,
|
||||
"vpn": vpn}})
|
||||
inst = self.instdir.new()
|
||||
inst['mac_address'] = allocate_result['result']['mac_address']
|
||||
inst['private_dns_name'] = allocate_result['result']['ip_address']
|
||||
inst['image_id'] = image_id
|
||||
inst['kernel_id'] = kernel_id
|
||||
inst['ramdisk_id'] = ramdisk_id
|
||||
@@ -558,24 +577,9 @@ class CloudController(object):
|
||||
inst['key_name'] = kwargs.get('key_name', '')
|
||||
inst['user_id'] = context.user.id
|
||||
inst['project_id'] = context.project.id
|
||||
inst['mac_address'] = utils.generate_mac()
|
||||
inst['ami_launch_index'] = num
|
||||
inst['bridge_name'] = bridge_name
|
||||
if FLAGS.simple_network:
|
||||
address = network.allocate_simple_ip()
|
||||
else:
|
||||
if inst['image_id'] == FLAGS.vpn_image_id:
|
||||
address = network.allocate_vpn_ip(
|
||||
inst['user_id'],
|
||||
inst['project_id'],
|
||||
mac=inst['mac_address'])
|
||||
else:
|
||||
address = network.allocate_ip(
|
||||
inst['user_id'],
|
||||
inst['project_id'],
|
||||
mac=inst['mac_address'])
|
||||
inst['private_dns_name'] = str(address)
|
||||
# TODO: allocate expresses on the router node
|
||||
|
||||
inst.save()
|
||||
rpc.cast(FLAGS.compute_topic,
|
||||
{"method": "run_instance",
|
||||
@@ -583,8 +587,7 @@ class CloudController(object):
|
||||
logging.debug("Casting to node for %s's instance with IP of %s" %
|
||||
(context.user.name, inst['private_dns_name']))
|
||||
# TODO: Make Network figure out the network name from ip.
|
||||
return defer.succeed(self._format_instances(
|
||||
context, reservation_id))
|
||||
defer.returnValue(self._format_instances(context, reservation_id))
|
||||
|
||||
@rbac.allow('projectmanager', 'sysadmin')
|
||||
def terminate_instances(self, context, instance_id, **kwargs):
|
||||
@@ -594,26 +597,34 @@ class CloudController(object):
|
||||
try:
|
||||
instance = self._get_instance(context, i)
|
||||
except exception.NotFound:
|
||||
logging.warning("Instance %s was not found during terminate" % i)
|
||||
logging.warning("Instance %s was not found during terminate"
|
||||
% i)
|
||||
continue
|
||||
try:
|
||||
self.network.disassociate_address(
|
||||
instance.get('public_dns_name', 'bork'))
|
||||
except:
|
||||
pass
|
||||
if instance.get('private_dns_name', None):
|
||||
logging.debug("Deallocating address %s" % instance.get('private_dns_name', None))
|
||||
if FLAGS.simple_network:
|
||||
network.deallocate_simple_ip(instance.get('private_dns_name', None))
|
||||
else:
|
||||
try:
|
||||
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
|
||||
elastic_ip = instance.get('public_dns_name', None)
|
||||
if elastic_ip:
|
||||
logging.debug("Deallocating address %s" % elastic_ip)
|
||||
# NOTE(vish): Right now we don't really care if the ip is
|
||||
# disassociated. We may need to worry about
|
||||
# checking this later. Perhaps in the scheduler?
|
||||
rpc.cast(self._get_network_host(context),
|
||||
{"method": "disassociate_elastic_ip",
|
||||
"args": {"elastic_ip": elastic_ip}})
|
||||
|
||||
fixed_ip = instance.get('private_dns_name', None)
|
||||
if fixed_ip:
|
||||
logging.debug("Deallocating address %s" % fixed_ip)
|
||||
# NOTE(vish): Right now we don't really care if the ip is
|
||||
# actually removed. We may need to worry about
|
||||
# checking this later. Perhaps in the scheduler?
|
||||
rpc.cast(self._get_network_host(context),
|
||||
{"method": "deallocate_fixed_ip",
|
||||
"args": {"elastic_ip": elastic_ip}})
|
||||
|
||||
if instance.get('node_name', 'unassigned') != 'unassigned':
|
||||
# NOTE(joshua?): It's also internal default
|
||||
rpc.cast('%s.%s' % (FLAGS.compute_topic, instance['node_name']),
|
||||
{"method": "terminate_instance",
|
||||
"args" : {"instance_id": i}})
|
||||
{"method": "terminate_instance",
|
||||
"args": {"instance_id": i}})
|
||||
else:
|
||||
instance.destroy()
|
||||
return defer.succeed(True)
|
||||
|
||||
@@ -24,8 +24,9 @@ from nova import flags
|
||||
from nova import test
|
||||
from nova import utils
|
||||
from nova.auth import manager
|
||||
from nova.compute import network
|
||||
from nova.compute.exception import NoMoreAddresses
|
||||
from nova.network import model
|
||||
from nova.network import service
|
||||
from nova.network.exception import NoMoreAddresses
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
@@ -52,7 +53,8 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
self.projects.append(self.manager.create_project(name,
|
||||
'netuser',
|
||||
name))
|
||||
self.network = network.PublicNetworkController()
|
||||
self.network = model.PublicNetworkController()
|
||||
self.service = service.VlanNetworkService()
|
||||
|
||||
def tearDown(self):
|
||||
super(NetworkTestCase, self).tearDown()
|
||||
@@ -66,16 +68,17 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
self.assertTrue(IPy.IP(address) in pubnet)
|
||||
self.assertTrue(IPy.IP(address) in self.network.network)
|
||||
|
||||
def test_allocate_deallocate_ip(self):
|
||||
address = network.allocate_ip(
|
||||
self.user.id, self.projects[0].id, utils.generate_mac())
|
||||
def test_allocate_deallocate_fixed_ip(self):
|
||||
result = self.service.allocate_fixed_ip(
|
||||
self.user.id, self.projects[0].id)
|
||||
address = result['ip']
|
||||
mac = result['mac']
|
||||
logging.debug("Was allocated %s" % (address))
|
||||
net = network.get_project_network(self.projects[0].id, "default")
|
||||
net = model.get_project_network(self.projects[0].id, "default")
|
||||
self.assertEqual(True, is_in_project(address, self.projects[0].id))
|
||||
mac = utils.generate_mac()
|
||||
hostname = "test-host"
|
||||
self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name)
|
||||
rv = network.deallocate_ip(address)
|
||||
rv = self.service.deallocate_fixed_ip(address)
|
||||
|
||||
# Doesn't go away until it's dhcp released
|
||||
self.assertEqual(True, is_in_project(address, self.projects[0].id))
|
||||
@@ -84,15 +87,18 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
self.assertEqual(False, is_in_project(address, self.projects[0].id))
|
||||
|
||||
def test_range_allocation(self):
|
||||
mac = utils.generate_mac()
|
||||
secondmac = utils.generate_mac()
|
||||
hostname = "test-host"
|
||||
address = network.allocate_ip(
|
||||
self.user.id, self.projects[0].id, mac)
|
||||
secondaddress = network.allocate_ip(
|
||||
self.user, self.projects[1].id, secondmac)
|
||||
net = network.get_project_network(self.projects[0].id, "default")
|
||||
secondnet = network.get_project_network(self.projects[1].id, "default")
|
||||
result = self.service.allocate_fixed_ip(
|
||||
self.user.id, self.projects[0].id)
|
||||
mac = result['mac']
|
||||
address = result['ip']
|
||||
result = self.service.allocate_fixed_ip(
|
||||
self.user, self.projects[1].id)
|
||||
secondmac = result['mac']
|
||||
secondaddress = result['ip']
|
||||
|
||||
net = model.get_project_network(self.projects[0].id, "default")
|
||||
secondnet = model.get_project_network(self.projects[1].id, "default")
|
||||
|
||||
self.assertEqual(True, is_in_project(address, self.projects[0].id))
|
||||
self.assertEqual(True, is_in_project(secondaddress, self.projects[1].id))
|
||||
@@ -103,46 +109,50 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
self.dnsmasq.issue_ip(secondmac, secondaddress,
|
||||
hostname, secondnet.bridge_name)
|
||||
|
||||
rv = network.deallocate_ip(address)
|
||||
rv = self.service.deallocate_fixed_ip(address)
|
||||
self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
|
||||
self.assertEqual(False, is_in_project(address, self.projects[0].id))
|
||||
|
||||
# First address release shouldn't affect the second
|
||||
self.assertEqual(True, is_in_project(secondaddress, self.projects[1].id))
|
||||
|
||||
rv = network.deallocate_ip(secondaddress)
|
||||
rv = self.service.deallocate_fixed_ip(secondaddress)
|
||||
self.dnsmasq.release_ip(secondmac, secondaddress,
|
||||
hostname, secondnet.bridge_name)
|
||||
self.assertEqual(False, is_in_project(secondaddress, self.projects[1].id))
|
||||
|
||||
def test_subnet_edge(self):
|
||||
secondaddress = network.allocate_ip(self.user.id, self.projects[0].id,
|
||||
utils.generate_mac())
|
||||
result = self.service.allocate_fixed_ip(self.user.id,
|
||||
self.projects[0].id)
|
||||
firstaddress = result['ip']
|
||||
hostname = "toomany-hosts"
|
||||
for i in range(1,5):
|
||||
project_id = self.projects[i].id
|
||||
mac = utils.generate_mac()
|
||||
mac2 = utils.generate_mac()
|
||||
mac3 = utils.generate_mac()
|
||||
address = network.allocate_ip(
|
||||
self.user, project_id, mac)
|
||||
address2 = network.allocate_ip(
|
||||
self.user, project_id, mac2)
|
||||
address3 = network.allocate_ip(
|
||||
self.user, project_id, mac3)
|
||||
result = self.service.allocate_fixed_ip(
|
||||
self.user, project_id)
|
||||
mac = result['mac']
|
||||
address = result['ip']
|
||||
result = self.service.allocate_fixed_ip(
|
||||
self.user, project_id)
|
||||
mac2 = result['mac']
|
||||
address2 = result['ip']
|
||||
result = self.service.allocate_fixed_ip(
|
||||
self.user, project_id)
|
||||
mac3 = result['mac']
|
||||
address3 = result['ip']
|
||||
self.assertEqual(False, is_in_project(address, self.projects[0].id))
|
||||
self.assertEqual(False, is_in_project(address2, self.projects[0].id))
|
||||
self.assertEqual(False, is_in_project(address3, self.projects[0].id))
|
||||
rv = network.deallocate_ip(address)
|
||||
rv = network.deallocate_ip(address2)
|
||||
rv = network.deallocate_ip(address3)
|
||||
net = network.get_project_network(project_id, "default")
|
||||
rv = self.service.deallocate_fixed_ip(address)
|
||||
rv = self.service.deallocate_fixed_ip(address2)
|
||||
rv = self.service.deallocate_fixed_ip(address3)
|
||||
net = model.get_project_network(project_id, "default")
|
||||
self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
|
||||
self.dnsmasq.release_ip(mac2, address2, hostname, net.bridge_name)
|
||||
self.dnsmasq.release_ip(mac3, address3, hostname, net.bridge_name)
|
||||
net = network.get_project_network(self.projects[0].id, "default")
|
||||
rv = network.deallocate_ip(secondaddress)
|
||||
self.dnsmasq.release_ip(mac, secondaddress, hostname, net.bridge_name)
|
||||
net = model.get_project_network(self.projects[0].id, "default")
|
||||
rv = self.service.deallocate_fixed_ip(firstaddress)
|
||||
self.dnsmasq.release_ip(mac, firstaddress, hostname, net.bridge_name)
|
||||
|
||||
def test_release_before_deallocate(self):
|
||||
pass
|
||||
@@ -169,7 +179,7 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
NUM_RESERVED_VPN_IPS)
|
||||
usable addresses
|
||||
"""
|
||||
net = network.get_project_network(self.projects[0].id, "default")
|
||||
net = model.get_project_network(self.projects[0].id, "default")
|
||||
|
||||
# Determine expected number of available IP addresses
|
||||
num_static_ips = net.num_static_ips
|
||||
@@ -183,22 +193,23 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
macs = {}
|
||||
addresses = {}
|
||||
for i in range(0, (num_available_ips - 1)):
|
||||
macs[i] = utils.generate_mac()
|
||||
addresses[i] = network.allocate_ip(self.user.id, self.projects[0].id, macs[i])
|
||||
result = self.service.allocate_fixed_ip(self.user.id, self.projects[0].id)
|
||||
macs[i] = result['mac']
|
||||
addresses[i] = result['ip']
|
||||
self.dnsmasq.issue_ip(macs[i], addresses[i], hostname, net.bridge_name)
|
||||
|
||||
self.assertRaises(NoMoreAddresses, network.allocate_ip, self.user.id, self.projects[0].id, utils.generate_mac())
|
||||
self.assertRaises(NoMoreAddresses, self.service.allocate_fixed_ip, self.user.id, self.projects[0].id)
|
||||
|
||||
for i in range(0, (num_available_ips - 1)):
|
||||
rv = network.deallocate_ip(addresses[i])
|
||||
rv = self.service.deallocate_fixed_ip(addresses[i])
|
||||
self.dnsmasq.release_ip(macs[i], addresses[i], hostname, net.bridge_name)
|
||||
|
||||
def is_in_project(address, project_id):
|
||||
return address in network.get_project_network(project_id).list_addresses()
|
||||
return address in model.get_project_network(project_id).list_addresses()
|
||||
|
||||
def _get_project_addresses(project_id):
|
||||
project_addresses = []
|
||||
for addr in network.get_project_network(project_id).list_addresses():
|
||||
for addr in model.get_project_network(project_id).list_addresses():
|
||||
project_addresses.append(addr)
|
||||
return project_addresses
|
||||
|
||||
|
||||
Reference in New Issue
Block a user