Got dhcpleasor working, with test ENV for testing, and rpc.cast for real world.
This commit is contained in:
parent
b7ea2f7058
commit
dbe324f725
@ -27,32 +27,50 @@ sys.path.append(os.path.abspath(os.path.join(__file__, "../../")))
|
|||||||
logging.debug(sys.path)
|
logging.debug(sys.path)
|
||||||
import getopt
|
import getopt
|
||||||
from os import environ
|
from os import environ
|
||||||
|
from nova.compute import linux_net
|
||||||
from nova.compute import network
|
from nova.compute import network
|
||||||
|
from nova import rpc
|
||||||
|
|
||||||
from nova import flags
|
from nova import flags
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
|
|
||||||
def add_lease(mac, ip, hostname, interface):
|
def add_lease(mac, ip, hostname, interface):
|
||||||
pass
|
if FLAGS.fake_rabbit:
|
||||||
|
network.lease_ip(ip)
|
||||||
|
else:
|
||||||
|
rpc.cast(FLAGS.cloud_topic, {"method": "lease_ip",
|
||||||
|
"args" : {"address": ip}})
|
||||||
|
|
||||||
def old_lease(mac, ip, hostname, interface):
|
def old_lease(mac, ip, hostname, interface):
|
||||||
pass
|
logging.debug("Adopted old lease or got a change of mac/hostname")
|
||||||
|
|
||||||
def del_lease(mac, ip, hostname, interface):
|
def del_lease(mac, ip, hostname, interface):
|
||||||
# TODO - get net from interface instead
|
if FLAGS.fake_rabbit:
|
||||||
net = network.get_network_by_address(ip)
|
network.release_ip(ip)
|
||||||
net.release_ip(ip)
|
else:
|
||||||
|
rpc.cast(FLAGS.cloud_topic, {"method": "release_ip",
|
||||||
|
"args" : {"address": ip}})
|
||||||
|
|
||||||
def init_leases(interface):
|
def init_leases(interface):
|
||||||
return ""
|
net = network.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])
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
def main(argv=None):
|
def main(argv=None):
|
||||||
if argv is None:
|
if argv is None:
|
||||||
argv = sys.argv
|
argv = sys.argv
|
||||||
interface = environ.get('DNSMASQ_INTERFACE', 'br0')
|
interface = environ.get('DNSMASQ_INTERFACE', 'br0')
|
||||||
old_redis_db = FLAGS.redis_db
|
if int(environ.get('TESTING', '0')):
|
||||||
FLAGS.redis_db = int(environ.get('REDIS_DB', '0'))
|
FLAGS.fake_rabbit = True
|
||||||
|
FLAGS.redis_db = 8
|
||||||
|
FLAGS.network_size = 32
|
||||||
|
FLAGS.fake_libvirt=True
|
||||||
|
FLAGS.fake_network=True
|
||||||
|
FLAGS.fake_users = True
|
||||||
action = argv[1]
|
action = argv[1]
|
||||||
if action in ['add','del','old']:
|
if action in ['add','del','old']:
|
||||||
mac = argv[2]
|
mac = argv[2]
|
||||||
@ -62,7 +80,7 @@ def main(argv=None):
|
|||||||
globals()[action+'_lease'](mac, ip, hostname, interface)
|
globals()[action+'_lease'](mac, ip, hostname, interface)
|
||||||
else:
|
else:
|
||||||
print init_leases(interface)
|
print init_leases(interface)
|
||||||
FLAGS.redis_db = old_redis_db
|
exit(0)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
sys.exit(main())
|
sys.exit(main())
|
||||||
|
@ -16,7 +16,7 @@ import sys, os
|
|||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
#sys.path.append(os.path.abspath('.'))
|
sys.path.append(os.path.abspath('/Users/jmckenty/Projects/cc'))
|
||||||
sys.path.append([os.path.abspath('../nova'),os.path.abspath('../'),os.path.abspath('../vendor')])
|
sys.path.append([os.path.abspath('../nova'),os.path.abspath('../'),os.path.abspath('../vendor')])
|
||||||
from nova import vendor
|
from nova import vendor
|
||||||
|
|
||||||
|
@ -98,11 +98,10 @@ def dnsmasq_cmd(net):
|
|||||||
' --pid-file=%s' % dhcp_file(net['vlan'], 'pid'),
|
' --pid-file=%s' % dhcp_file(net['vlan'], 'pid'),
|
||||||
' --listen-address=%s' % net.dhcp_listen_address,
|
' --listen-address=%s' % net.dhcp_listen_address,
|
||||||
' --except-interface=lo',
|
' --except-interface=lo',
|
||||||
' --dhcp-range=%s,static,120s' % (net.dhcp_range_start),
|
' --dhcp-range=%s,static,600s' % (net.dhcp_range_start),
|
||||||
' --dhcp-lease-max=61',
|
|
||||||
' --dhcp-hostsfile=%s' % dhcp_file(net['vlan'], 'conf'),
|
' --dhcp-hostsfile=%s' % dhcp_file(net['vlan'], 'conf'),
|
||||||
' --dhcp-leasefile=%s' % dhcp_file(net['vlan'], 'leases'),
|
' --dhcp-script=%s' % bin_file('dhcpleasor.py'),
|
||||||
' ---dhcp-script=%s' % bin_file('dhcpleasor.py')]
|
' --leasefile-ro']
|
||||||
return ''.join(cmd)
|
return ''.join(cmd)
|
||||||
|
|
||||||
def hostDHCP(network, host, mac):
|
def hostDHCP(network, host, mac):
|
||||||
|
@ -160,7 +160,10 @@ class BaseNetwork(datastore.RedisModel):
|
|||||||
self._add_host(user_id, project_id, address, mac)
|
self._add_host(user_id, project_id, address, mac)
|
||||||
self.express(address=address)
|
self.express(address=address)
|
||||||
return address
|
return address
|
||||||
raise exception.NoMoreAddresses()
|
raise exception.NoMoreAddresses("Project %s with network %s" % (project_id, str(self.network)))
|
||||||
|
|
||||||
|
def lease_ip(self, ip_str):
|
||||||
|
logging.debug("Leasing allocated IP %s" % (ip_str))
|
||||||
|
|
||||||
def release_ip(self, ip_str):
|
def release_ip(self, ip_str):
|
||||||
if not ip_str in self.assigned:
|
if not ip_str in self.assigned:
|
||||||
@ -419,14 +422,22 @@ def get_vlan_for_project(project_id):
|
|||||||
return vlan
|
return vlan
|
||||||
raise exception.AddressNotAllocated("Out of VLANs")
|
raise exception.AddressNotAllocated("Out of VLANs")
|
||||||
|
|
||||||
|
def get_project_id_for_vlan(vlan):
|
||||||
|
assigned_vlans = get_assigned_vlans()
|
||||||
|
for project_id, project_vlan in assigned_vlans.iteritems():
|
||||||
|
if vlan == project_vlan:
|
||||||
|
return project_id
|
||||||
|
|
||||||
|
def get_network_by_interface(iface, security_group='default'):
|
||||||
|
vlan = iface.rpartition("br")[2]
|
||||||
|
return get_project_network(get_project_id_for_vlan(vlan), security_group)
|
||||||
|
|
||||||
def get_network_by_address(address):
|
def get_network_by_address(address):
|
||||||
logging.debug("Get Network By Address:")
|
logging.debug("Get Network By Address: %s" % address)
|
||||||
for project in users.UserManager.instance().get_projects():
|
for project in users.UserManager.instance().get_projects():
|
||||||
logging.debug(" looking at project %s", project.id)
|
|
||||||
net = get_project_network(project.id)
|
net = get_project_network(project.id)
|
||||||
logging.debug(" is %s in %s ?" % (address, str(net.assigned)))
|
|
||||||
if address in net.assigned:
|
if address in net.assigned:
|
||||||
|
logging.debug("Found %s in %s" % (address, project.id))
|
||||||
return net
|
return net
|
||||||
raise exception.AddressNotAllocated()
|
raise exception.AddressNotAllocated()
|
||||||
|
|
||||||
@ -438,6 +449,12 @@ def allocate_ip(user_id, project_id, mac):
|
|||||||
|
|
||||||
def deallocate_ip(address):
|
def deallocate_ip(address):
|
||||||
return get_network_by_address(address).deallocate_ip(address)
|
return get_network_by_address(address).deallocate_ip(address)
|
||||||
|
|
||||||
|
def release_ip(address):
|
||||||
|
return get_network_by_address(address).release_ip(address)
|
||||||
|
|
||||||
|
def lease_ip(address):
|
||||||
|
return get_network_by_address(address).lease_ip(address)
|
||||||
|
|
||||||
def get_project_network(project_id, security_group='default'):
|
def get_project_network(project_id, security_group='default'):
|
||||||
""" get a project's private network, allocating one if needed """
|
""" get a project's private network, allocating one if needed """
|
||||||
|
@ -498,6 +498,14 @@ class CloudController(object):
|
|||||||
# TODO - Strip the IP from the instance
|
# TODO - Strip the IP from the instance
|
||||||
return defer.succeed({'disassociateResponse': ["Address disassociated."]})
|
return defer.succeed({'disassociateResponse': ["Address disassociated."]})
|
||||||
|
|
||||||
|
def release_ip(self, context, private_ip, **kwargs):
|
||||||
|
self.network.release_ip(private_ip)
|
||||||
|
return defer.succeed({'releaseResponse': ["Address released."]})
|
||||||
|
|
||||||
|
def lease_ip(self, context, private_ip, **kwargs):
|
||||||
|
self.network.lease_ip(private_ip)
|
||||||
|
return defer.succeed({'leaseResponse': ["Address lease."]})
|
||||||
|
|
||||||
@rbac.allow('projectmanager', 'sysadmin')
|
@rbac.allow('projectmanager', 'sysadmin')
|
||||||
def run_instances(self, context, **kwargs):
|
def run_instances(self, context, **kwargs):
|
||||||
# make sure user can access the image
|
# make sure user can access the image
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
import unittest
|
import unittest
|
||||||
|
import time
|
||||||
|
|
||||||
from nova import vendor
|
from nova import vendor
|
||||||
import IPy
|
import IPy
|
||||||
@ -86,18 +87,36 @@ class NetworkTestCase(test.TrialTestCase):
|
|||||||
self.assertEqual(False, address in self._get_project_addresses("project0"))
|
self.assertEqual(False, address in self._get_project_addresses("project0"))
|
||||||
|
|
||||||
def test_range_allocation(self):
|
def test_range_allocation(self):
|
||||||
|
mac = utils.generate_mac()
|
||||||
|
secondmac = utils.generate_mac()
|
||||||
|
hostname = "test-host"
|
||||||
address = network.allocate_ip(
|
address = network.allocate_ip(
|
||||||
"netuser", "project0", utils.generate_mac())
|
"netuser", "project0", mac)
|
||||||
secondaddress = network.allocate_ip(
|
secondaddress = network.allocate_ip(
|
||||||
"netuser", "project1", utils.generate_mac())
|
"netuser", "project1", secondmac)
|
||||||
|
net = network.get_project_network("project0", "default")
|
||||||
|
secondnet = network.get_project_network("project1", "default")
|
||||||
|
|
||||||
self.assertEqual(True,
|
self.assertEqual(True,
|
||||||
address in self._get_project_addresses("project0"))
|
address in self._get_project_addresses("project0"))
|
||||||
self.assertEqual(True,
|
self.assertEqual(True,
|
||||||
secondaddress in self._get_project_addresses("project1"))
|
secondaddress in self._get_project_addresses("project1"))
|
||||||
self.assertEqual(False, address in self._get_project_addresses("project1"))
|
self.assertEqual(False, address in self._get_project_addresses("project1"))
|
||||||
|
# Addresses are allocated before they're issued
|
||||||
|
self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name)
|
||||||
|
self.dnsmasq.issue_ip(secondmac, secondaddress,
|
||||||
|
hostname, secondnet.bridge_name)
|
||||||
|
|
||||||
rv = network.deallocate_ip(address)
|
rv = network.deallocate_ip(address)
|
||||||
|
self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
|
||||||
self.assertEqual(False, address in self._get_project_addresses("project0"))
|
self.assertEqual(False, address in self._get_project_addresses("project0"))
|
||||||
|
# First address release shouldn't affect the second
|
||||||
|
self.assertEqual(True,
|
||||||
|
secondaddress in self._get_project_addresses("project1"))
|
||||||
|
|
||||||
rv = network.deallocate_ip(secondaddress)
|
rv = network.deallocate_ip(secondaddress)
|
||||||
|
self.dnsmasq.release_ip(secondmac, secondaddress,
|
||||||
|
hostname, secondnet.bridge_name)
|
||||||
self.assertEqual(False,
|
self.assertEqual(False,
|
||||||
secondaddress in self._get_project_addresses("project1"))
|
secondaddress in self._get_project_addresses("project1"))
|
||||||
|
|
||||||
@ -127,9 +146,14 @@ class NetworkTestCase(test.TrialTestCase):
|
|||||||
for i in range(0, 30):
|
for i in range(0, 30):
|
||||||
name = 'toomany-project%s' % i
|
name = 'toomany-project%s' % i
|
||||||
self.manager.create_project(name, 'netuser', name)
|
self.manager.create_project(name, 'netuser', name)
|
||||||
|
net = network.get_project_network(name, "default")
|
||||||
|
mac = utils.generate_mac()
|
||||||
|
hostname = "toomany-hosts"
|
||||||
address = network.allocate_ip(
|
address = network.allocate_ip(
|
||||||
"netuser", name, utils.generate_mac())
|
"netuser", name, mac)
|
||||||
|
self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name)
|
||||||
rv = network.deallocate_ip(address)
|
rv = network.deallocate_ip(address)
|
||||||
|
self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
|
||||||
self.manager.delete_project(name)
|
self.manager.delete_project(name)
|
||||||
|
|
||||||
def _get_project_addresses(self, project_id):
|
def _get_project_addresses(self, project_id):
|
||||||
@ -144,15 +168,13 @@ def binpath(script):
|
|||||||
class FakeDNSMasq(object):
|
class FakeDNSMasq(object):
|
||||||
def issue_ip(self, mac, ip, hostname, interface):
|
def issue_ip(self, mac, ip, hostname, interface):
|
||||||
cmd = "%s add %s %s %s" % (binpath('dhcpleasor.py'), mac, ip, hostname)
|
cmd = "%s add %s %s %s" % (binpath('dhcpleasor.py'), mac, ip, hostname)
|
||||||
env = {'DNSMASQ_INTERFACE': interface, 'REDIS_DB' : '8'}
|
env = {'DNSMASQ_INTERFACE': interface, 'TESTING' : '1'}
|
||||||
(out, err) = utils.execute(cmd, addl_env=env)
|
(out, err) = utils.execute(cmd, addl_env=env)
|
||||||
logging.debug(out)
|
logging.debug("ISSUE_IP: %s, %s " % (out, err))
|
||||||
logging.debug(err)
|
|
||||||
|
|
||||||
def release_ip(self, mac, ip, hostname, interface):
|
def release_ip(self, mac, ip, hostname, interface):
|
||||||
cmd = "%s del %s %s %s" % (binpath('dhcpleasor.py'), mac, ip, hostname)
|
cmd = "%s del %s %s %s" % (binpath('dhcpleasor.py'), mac, ip, hostname)
|
||||||
env = {'DNSMASQ_INTERFACE': interface, 'REDIS_DB' : '8'}
|
env = {'DNSMASQ_INTERFACE': interface, 'TESTING' : '1'}
|
||||||
(out, err) = utils.execute(cmd, addl_env=env)
|
(out, err) = utils.execute(cmd, addl_env=env)
|
||||||
logging.debug(out)
|
logging.debug("RELEASE_IP: %s, %s " % (out, err))
|
||||||
logging.debug(err)
|
|
||||||
|
|
@ -48,11 +48,9 @@ def fetchfile(url, target):
|
|||||||
execute("curl %s -o %s" % (url, target))
|
execute("curl %s -o %s" % (url, target))
|
||||||
|
|
||||||
def execute(cmd, input=None, addl_env=None):
|
def execute(cmd, input=None, addl_env=None):
|
||||||
#logging.debug("Running %s" % (cmd))
|
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
if addl_env:
|
if addl_env:
|
||||||
env.update(addl_env)
|
env.update(addl_env)
|
||||||
logging.debug(env)
|
|
||||||
obj = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
|
obj = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
|
||||||
result = None
|
result = None
|
||||||
|
Loading…
Reference in New Issue
Block a user