Rajaram/Vinkesh | Added IpRoute model. Started using melange.conf.sample for tests

This commit is contained in:
vinkesh banka 2011-09-28 15:35:05 +05:30 committed by Rajaram Mallya
parent 80bd741881
commit 1b94bc7df1
15 changed files with 117 additions and 105 deletions

View File

@ -50,6 +50,7 @@ def _configure_db_session(conf):
def _load_app_environment(): def _load_app_environment():
oparser = optparse.OptionParser() oparser = optparse.OptionParser()
config.add_common_options(oparser)
config.add_log_options(oparser) config.add_log_options(oparser)
(options, args) = config.parse_options(oparser) (options, args) = config.parse_options(oparser)
conf = config.Config.load_paste_config('melange', options, args) conf = config.Config.load_paste_config('melange', options, args)

View File

@ -14,7 +14,7 @@ bind_port = 9898
# SQLAlchemy connection string for the reference implementation # SQLAlchemy connection string for the reference implementation
# registry server. Any valid SQLAlchemy connection string is fine. # registry server. Any valid SQLAlchemy connection string is fine.
# See: http://www.sqlalchemy.org/docs/05/reference/sqlalchemy/connections.html#sqlalchemy.create_engine # See: http://www.sqlalchemy.org/docs/05/reference/sqlalchemy/connections.html#sqlalchemy.create_engine
sql_connection = sqlite:///melange.sqlite sql_connection = sqlite:///melange_test.sqlite
# Period in seconds after which SQLAlchemy should reestablish its connection # Period in seconds after which SQLAlchemy should reestablish its connection
# to the database. # to the database.

View File

@ -1,64 +0,0 @@
[DEFAULT]
# Show more verbose log output (sets INFO log level output)
verbose = False
# Show debugging output in logs (sets DEBUG log level output)
debug = False
# Path to the extensions
api_extensions_path = ../../melange/extensions
# Address to bind the API server
bind_host = 0.0.0.0
# Port the bind the API server to
bind_port = 9898
# SQLAlchemy connection string for the reference implementation
# registry server. Any valid SQLAlchemy connection string is fine.
# See: http://www.sqlalchemy.org/docs/05/reference/sqlalchemy/connections.html#sqlalchemy.create_engine
sql_connection = sqlite:///melange_test.sqlite
# Period in seconds after which SQLAlchemy should reestablish its connection
# to the database.
#
# MySQL uses a default `wait_timeout` of 8 hours, after which it will drop
# idle connections. This can result in 'MySQL Gone Away' exceptions. If you
# notice this, you can lower this value to ensure that SQLAlchemy reconnects
# before MySQL can drop the connection.
sql_idle_timeout = 3600
#DB Api Implementation
db_api_implementation = "melange.db.sqlalchemy.api"
# Cidr used for auto creating private ip block in a network
default_cidr = 10.0.0.0/24
#IPV6 Generator Factory
#ipv6_generator=melange.ipv6.tenant_based_generator.TenantBasedIpV6Generator
#DNS info for a data_center
nameserver = "ns.example.com"
#Number of retries for allocating an IP
ip_allocation_retries = 5
[pipeline:extensions_app_with_filter]
pipeline = extensions extensions_test_app
[filter:extensions]
paste.filter_factory = melange.common.extensions:factory
[app:extensions_test_app]
paste.app_factory = melange.tests.unit.test_extensions:app_factory
[composite:versioned_melange]
use = egg:Paste#urlmap
/: versions
/v0.1: melange
[app:versions]
paste.app_factory = melange.versions:app_factory
[app:melange]
paste.app_factory = melange.ipam.service:app_factory

View File

@ -28,12 +28,14 @@ def map(engine, models):
policies_table = Table('policies', meta, autoload=True) policies_table = Table('policies', meta, autoload=True)
ip_ranges_table = Table('ip_ranges', meta, autoload=True) ip_ranges_table = Table('ip_ranges', meta, autoload=True)
ip_octets_table = Table('ip_octets', meta, autoload=True) ip_octets_table = Table('ip_octets', meta, autoload=True)
ip_routes_table = Table('ip_routes', meta, autoload=True)
orm.mapper(models["IpBlock"], Table('ip_blocks', meta, autoload=True)) orm.mapper(models["IpBlock"], Table('ip_blocks', meta, autoload=True))
orm.mapper(models["IpAddress"], ip_addresses_table) orm.mapper(models["IpAddress"], ip_addresses_table)
orm.mapper(models["Policy"], policies_table) orm.mapper(models["Policy"], policies_table)
orm.mapper(models["IpRange"], ip_ranges_table) orm.mapper(models["IpRange"], ip_ranges_table)
orm.mapper(models["IpOctet"], ip_octets_table) orm.mapper(models["IpOctet"], ip_octets_table)
orm.mapper(models["IpRoute"], ip_routes_table)
inside_global_join = (ip_nats_table.c.inside_global_address_id inside_global_join = (ip_nats_table.c.inside_global_address_id
== ip_addresses_table.c.id) == ip_addresses_table.c.id)

View File

@ -35,7 +35,7 @@ ip_blocks = Table('ip_blocks', meta,
Column('id', String(36), primary_key=True, nullable=False), Column('id', String(36), primary_key=True, nullable=False),
Column('network_id', String(255)), Column('network_id', String(255)),
Column('cidr', String(255), nullable=False), Column('cidr', String(255), nullable=False),
Column('created_at', DateTime(), nullable=True), Column('created_at', DateTime()),
Column('updated_at', DateTime()), Column('updated_at', DateTime()),
Column('type', String(7)), Column('type', String(7)),
Column('tenant_id', String(255)), Column('tenant_id', String(255)),
@ -50,10 +50,9 @@ ip_blocks = Table('ip_blocks', meta,
ip_addresses = Table('ip_addresses', meta, ip_addresses = Table('ip_addresses', meta,
Column('id', String(36), primary_key=True, nullable=False), Column('id', String(36), primary_key=True, nullable=False),
Column('address', String(255), nullable=False), Column('address', String(255), nullable=False),
Column('interface_id', String(255), nullable=True), Column('interface_id', String(255)),
Column('ip_block_id', String(36), ForeignKey('ip_blocks.id'), Column('ip_block_id', String(36), ForeignKey('ip_blocks.id')),
nullable=True), Column('created_at', DateTime()),
Column('created_at', DateTime(), nullable=True),
Column('used_by_tenant', String(255)), Column('used_by_tenant', String(255)),
Column('used_by_device', String(255)), Column('used_by_device', String(255)),
Column('updated_at', DateTime()), Column('updated_at', DateTime()),
@ -80,8 +79,8 @@ policies = Table('policies', meta,
Column('id', String(36), primary_key=True, nullable=False), Column('id', String(36), primary_key=True, nullable=False),
Column('name', String(255), nullable=False), Column('name', String(255), nullable=False),
Column('tenant_id', String(255)), Column('tenant_id', String(255)),
Column('description', String(255), nullable=True), Column('description', String(255)),
Column('created_at', DateTime(), nullable=True), Column('created_at', DateTime()),
Column('updated_at', DateTime())) Column('updated_at', DateTime()))
@ -90,7 +89,7 @@ ip_ranges = Table('ip_ranges', meta,
Column('offset', Integer(), nullable=False), Column('offset', Integer(), nullable=False),
Column('length', Integer(), nullable=False), Column('length', Integer(), nullable=False),
Column('policy_id', String(36), ForeignKey('policies.id')), Column('policy_id', String(36), ForeignKey('policies.id')),
Column('created_at', DateTime(), nullable=True), Column('created_at', DateTime()),
Column('updated_at', DateTime())) Column('updated_at', DateTime()))
@ -98,17 +97,26 @@ ip_octets = Table('ip_octets', meta,
Column('id', String(36), primary_key=True, nullable=False), Column('id', String(36), primary_key=True, nullable=False),
Column('octet', Integer(), nullable=False), Column('octet', Integer(), nullable=False),
Column('policy_id', String(36), ForeignKey('policies.id')), Column('policy_id', String(36), ForeignKey('policies.id')),
Column('created_at', DateTime(), nullable=True), Column('created_at', DateTime()),
Column('updated_at', DateTime()))
ip_routes = Table('ip_routes', meta,
Column('id', String(36), primary_key=True, nullable=False),
Column('destination', String(255), nullable=False),
Column('netmask', String(255)),
Column('gateway', String(255), nullable=False),
Column('source_block_id', String(36), ForeignKey('ip_blocks.id')),
Column('created_at', DateTime()),
Column('updated_at', DateTime())) Column('updated_at', DateTime()))
def upgrade(migrate_engine): def upgrade(migrate_engine):
meta.bind = migrate_engine meta.bind = migrate_engine
create_tables([policies, ip_blocks, ip_addresses, ip_nats, ip_ranges, create_tables([policies, ip_ranges, ip_octets, ip_blocks, ip_routes,
ip_octets]) ip_addresses, ip_nats])
def downgrade(migrate_engine): def downgrade(migrate_engine):
meta.bind = migrate_engine meta.bind = migrate_engine
drop_tables([ip_nats, ip_blocks, ip_addresses, ip_ranges, ip_octets, drop_tables([ip_nats, ip_addresses, ip_routes, ip_blocks, ip_ranges,
policies]) ip_octets, policies])

View File

@ -623,6 +623,13 @@ class IpAddress(ModelBase):
return self.address return self.address
class IpRoute(ModelBase):
def _validate(self):
self._validate_presence_of("destination", "gateway")
self._validate_existence_of("source_block_id", IpBlock)
class Policy(ModelBase): class Policy(ModelBase):
_data_fields = ['name', 'description', 'tenant_id'] _data_fields = ['name', 'description', 'tenant_id']
@ -767,6 +774,7 @@ def persisted_models():
'Policy': Policy, 'Policy': Policy,
'IpRange': IpRange, 'IpRange': IpRange,
'IpOctet': IpOctet, 'IpOctet': IpOctet,
'IpRoute': IpRoute,
} }

View File

@ -45,7 +45,7 @@ class IpV6IpBlockFactory(IpBlockFactory):
class IpAddressFactory(factory.Factory): class IpAddressFactory(factory.Factory):
FACTORY_FOR = models.IpAddress FACTORY_FOR = models.IpAddress
ip_block_id = factory.LazyAttribute(lambda a: PublicIpBlockFactory().id) ip_block_id = factory.LazyAttribute(lambda a: IpBlockFactory().id)
@factory.lazy_attribute_sequence @factory.lazy_attribute_sequence
def address(ip, n): def address(ip, n):
@ -53,6 +53,14 @@ class IpAddressFactory(factory.Factory):
return netaddr.IPNetwork(ip_block.cidr)[int(n)] return netaddr.IPNetwork(ip_block.cidr)[int(n)]
class IpRouteFactory(factory.Factory):
FACTORY_FOR = models.IpRoute
destination = factory.Sequence(lambda n: "10.0.0.{0}".format(int(n) % 255))
netmask = "255.255.192.0"
source_block_id = factory.LazyAttribute(lambda a: IpBlockFactory().id)
gateway = "192.168.0.1"
class IpRangeFactory(factory.Factory): class IpRangeFactory(factory.Factory):
FACTORY_FOR = models.IpRange FACTORY_FOR = models.IpRange
offset = 0 offset = 0

View File

@ -16,7 +16,6 @@
# under the License. # under the License.
import os import os
import shutil
import socket import socket
import subprocess import subprocess
@ -29,24 +28,27 @@ from melange.tests.functional import server
_PORT = None _PORT = None
def test_config_file():
return melange.melange_etc_path("melange.conf.sample")
def setup(): def setup():
print "Restarting melange server..." print "Restarting melange server..."
shutil.copyfile(melange.melange_etc_path("melange.conf.sample"),
os.path.expanduser("~/melange.conf"))
srv = server.Server("melange", srv = server.Server("melange",
melange.melange_bin_path('melange')) melange.melange_bin_path('melange'), )
_db_sync() options = dict(config_file=test_config_file())
srv.restart(port=setup_unused_port()) _db_sync(options)
_configure_db() srv.restart(port=setup_unused_port(), **options)
_configure_db(options)
def _configure_db(): def _configure_db(options):
conf = config.Config.load_paste_config("melange", {}, None) conf = config.Config.load_paste_config("melange", options, None)
db_api.configure_db(conf) db_api.configure_db(conf)
def _db_sync(): def _db_sync(options):
conf = config.Config.load_paste_config("melange", {}, None) conf = config.Config.load_paste_config("melange", options, None)
db_api.db_sync(conf) db_api.db_sync(conf)

View File

@ -27,17 +27,18 @@ class Server(object):
self.name = name self.name = name
self.path = path self.path = path
def restart(self, port): def restart(self, port, config_file):
self.stop() self.stop()
self.start(port) self.start(port, config_file)
def start(self, port): def start(self, port, config_file):
pid = os.fork() pid = os.fork()
if pid == 0: if pid == 0:
os.setsid() os.setsid()
self._close_stdio() self._close_stdio()
try: try:
os.system("(%s -p %s >func_test.log)" % (self.path, port)) os.system("(%s -p %s --config-file=%s >func_test.log)" %
(self.path, port, config_file))
except OSError: except OSError:
os._exit(1) os._exit(1)
os._exit(0) os._exit(0)

View File

@ -381,16 +381,14 @@ class TestIpAddressCLI(tests.BaseTest):
class TestDBSyncCLI(tests.BaseTest): class TestDBSyncCLI(tests.BaseTest):
def test_db_sync_executes(self): def test_db_sync_executes(self):
exitcode, out, err = functional.execute("{0} db_sync".format( exitcode, out, err = run_melange_manage("db_sync")
melange.melange_bin_path('melange-manage')))
self.assertEqual(exitcode, 0) self.assertEqual(exitcode, 0)
class TestDBUpgradeCLI(tests.BaseTest): class TestDBUpgradeCLI(tests.BaseTest):
def test_db_upgrade_executes(self): def test_db_upgrade_executes(self):
exitcode, out, err = functional.execute("{0} db_upgrade".format( exitcode, out, err = run_melange_manage("db_upgrade")
melange.melange_bin_path('melange-manage')))
self.assertEqual(exitcode, 0) self.assertEqual(exitcode, 0)
@ -404,8 +402,9 @@ class TestDeleteDeallocatedIps(tests.BaseTest):
days = config.Config.get('keep_deallocated_ips_for_days') days = config.Config.get('keep_deallocated_ips_for_days')
self._push_back_deallocated_date(ip, days) self._push_back_deallocated_date(ip, days)
exitcode, out, err = functional.execute( script = melange.melange_bin_path('melange-delete-deallocated-ips')
melange.melange_bin_path('melange-delete-deallocated-ips')) config_file = functional.test_config_file()
functional.execute("{0} --config-file={1}".format(script, config_file))
self.assertIsNone(models.IpAddress.get(ip.id)) self.assertIsNone(models.IpAddress.get(ip.id))
@ -414,3 +413,10 @@ class TestDeleteDeallocatedIps(tests.BaseTest):
deallocated_ip = models.IpAddress.find(ip.id) deallocated_ip = models.IpAddress.find(ip.id)
new_deallocated_date = deallocated_ip.deallocated_at - days_to_subtract new_deallocated_date = deallocated_ip.deallocated_at - days_to_subtract
deallocated_ip.update(deallocated_at=(new_deallocated_date)) deallocated_ip.update(deallocated_at=(new_deallocated_date))
def run_melange_manage(command):
melange_manage = melange.melange_bin_path('melange-manage')
config_file = functional.test_config_file()
return functional.execute("%(melange_manage)s %(command)s "
"--config-file=%(config_file)s" % locals())

View File

@ -31,7 +31,7 @@ from melange.db import db_api
def test_config_path(): def test_config_path():
return melange.melange_etc_path("melange.conf.test") return melange.melange_etc_path("melange.conf.sample")
def sanitize(data): def sanitize(data):
@ -80,7 +80,7 @@ class TestApp(webtest.TestApp):
def setup(): def setup():
options = {"config_file": test_config_path()} options = {"config_file": test_config_path()}
conf = config.Config.load_paste_config("melange", options, None) conf = config.Config.load_paste_config("melangeapp", options, None)
db_api.drop_db(conf) db_api.drop_db(conf)
db_api.db_sync(conf) db_api.db_sync(conf)

View File

@ -28,7 +28,7 @@ class TestExtensions(unittest.TestCase):
def test_extension_loads_with_melange_xmlns(self): def test_extension_loads_with_melange_xmlns(self):
options = {'config_file': unit.test_config_path()} options = {'config_file': unit.test_config_path()}
conf, app = config.Config.load_paste_app('extensions_app_with_filter', conf, app = config.Config.load_paste_app('melangeapi',
options, None) options, None)
test_app = webtest.TestApp(app) test_app = webtest.TestApp(app)

View File

@ -1160,6 +1160,46 @@ class TestIpAddress(tests.BaseTest):
self.assertEqual(ipv6.version, 6) self.assertEqual(ipv6.version, 6)
class TestIpRoute(tests.BaseTest):
def test_create(self):
block = factory_models.IpBlockFactory()
models.IpRoute.create(source_block_id=block.id,
destination="10.0.0.0",
netmask="255.255.192.0",
gateway="192.168.0.1")
created_route = models.IpRoute.find_by(source_block_id=block.id)
self.assertIsNotNone(created_route)
self.assertEqual(created_route.destination, "10.0.0.0")
self.assertEqual(created_route.netmask, "255.255.192.0")
self.assertEqual(created_route.gateway, "192.168.0.1")
def test_presence_of_destination(self):
ip_route = factory_models.IpRouteFactory.build(destination=None)
self.assertFalse(ip_route.is_valid())
self.assertEqual(ip_route.errors['destination'],
["destination should be present"])
def test_presence_of_gateway(self):
ip_route = factory_models.IpRouteFactory.build(gateway=None)
self.assertFalse(ip_route.is_valid())
self.assertEqual(ip_route.errors['gateway'],
["gateway should be present"])
def test_existence_of_source_block(self):
factory = factory_models.IpRouteFactory
ip_route = factory.build(source_block_id="invalid")
self.assertFalse(ip_route.is_valid())
self.assertEqual(ip_route.errors['source_block_id'],
["IpBlock with id = 'invalid' doesn't exist"])
class TestPolicy(tests.BaseTest): class TestPolicy(tests.BaseTest):
def test_create_policy(self): def test_create_policy(self):

View File

@ -36,7 +36,7 @@ class BaseTestController(tests.BaseTest):
def setUp(self): def setUp(self):
super(BaseTestController, self).setUp() super(BaseTestController, self).setUp()
conf, melange_app = config.Config.load_paste_app('melange', conf, melange_app = config.Config.load_paste_app('melangeapp',
{"config_file": unit.test_config_path()}, None) {"config_file": unit.test_config_path()}, None)
self.app = unit.TestApp(melange_app) self.app = unit.TestApp(melange_app)

View File

@ -25,7 +25,7 @@ from melange.tests import unit
class TestVersionsController(tests.BaseTest): class TestVersionsController(tests.BaseTest):
def setUp(self): def setUp(self):
conf, melange_app = config.Config.load_paste_app('versioned_melange', conf, melange_app = config.Config.load_paste_app('melange',
{"config_file": unit.test_config_path()}, None) {"config_file": unit.test_config_path()}, None)
self.test_app = webtest.TestApp(melange_app) self.test_app = webtest.TestApp(melange_app)
super(TestVersionsController, self).setUp() super(TestVersionsController, self).setUp()