From d27aa094a168dcfb486bbd49ef61be78bd5a50f2 Mon Sep 17 00:00:00 2001
From: Vishvananda Ishaya
Date: Wed, 23 Feb 2011 17:28:38 -0800
Subject: remove extra flag in admin tests
---
smoketests/admin_smoketests.py | 3 ---
1 file changed, 3 deletions(-)
diff --git a/smoketests/admin_smoketests.py b/smoketests/admin_smoketests.py
index 86a7f600d..cb3010965 100644
--- a/smoketests/admin_smoketests.py
+++ b/smoketests/admin_smoketests.py
@@ -35,10 +35,7 @@ from smoketests import flags
from smoketests import base
-SUITE_NAMES = '[user]'
-
FLAGS = flags.FLAGS
-flags.DEFINE_string('suite', None, 'Specific test suite to run ' + SUITE_NAMES)
# TODO(devamcar): Use random tempfile
ZIP_FILENAME = '/tmp/nova-me-x509.zip'
--
cgit
From 79d9e06d79264d614a465971dd43176bcf190703 Mon Sep 17 00:00:00 2001
From: Vishvananda Ishaya
Date: Wed, 23 Feb 2011 22:40:50 -0800
Subject: more smoketest fixes
---
smoketests/netadmin_smoketests.py | 5 -----
smoketests/sysadmin_smoketests.py | 6 ++++--
2 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/smoketests/netadmin_smoketests.py b/smoketests/netadmin_smoketests.py
index 38beb8fdc..16113e4a9 100644
--- a/smoketests/netadmin_smoketests.py
+++ b/smoketests/netadmin_smoketests.py
@@ -137,11 +137,6 @@ class SecurityGroupTests(base.UserSmokeTestCase):
if not self.wait_for_running(self.data['instance']):
self.fail('instance failed to start')
self.data['instance'].update()
- if not self.wait_for_ping(self.data['instance'].private_dns_name):
- self.fail('could not ping instance')
- if not self.wait_for_ssh(self.data['instance'].private_dns_name,
- TEST_KEY):
- self.fail('could not ssh to instance')
def test_003_can_authorize_security_group_ingress(self):
self.assertTrue(self.conn.authorize_security_group(TEST_GROUP,
diff --git a/smoketests/sysadmin_smoketests.py b/smoketests/sysadmin_smoketests.py
index e3b84d3d3..3b267bc65 100644
--- a/smoketests/sysadmin_smoketests.py
+++ b/smoketests/sysadmin_smoketests.py
@@ -191,7 +191,7 @@ class VolumeTests(base.UserSmokeTestCase):
self.assertEqual(volume.size, 1)
self.data['volume'] = volume
# Give network time to find volume.
- time.sleep(10)
+ time.sleep(5)
def test_002_can_attach_volume(self):
volume = self.data['volume']
@@ -204,6 +204,8 @@ class VolumeTests(base.UserSmokeTestCase):
else:
self.fail('cannot attach volume with state %s' % volume.status)
+ # Give volume some time to be ready.
+ time.sleep(5)
volume.attach(self.data['instance'].id, self.device)
# wait
@@ -218,7 +220,7 @@ class VolumeTests(base.UserSmokeTestCase):
self.assertTrue(volume.status.startswith('in-use'))
# Give instance time to recognize volume.
- time.sleep(10)
+ time.sleep(5)
def test_003_can_mount_volume(self):
ip = self.data['instance'].private_dns_name
--
cgit
From fc465b2a9f1c639e44e59c43cbe4d9a9a188f396 Mon Sep 17 00:00:00 2001
From: Vishvananda Ishaya
Date: Thu, 24 Feb 2011 00:25:21 -0800
Subject: fix check for existing port 22 rule
---
smoketests/netadmin_smoketests.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/smoketests/netadmin_smoketests.py b/smoketests/netadmin_smoketests.py
index 16113e4a9..54432242c 100644
--- a/smoketests/netadmin_smoketests.py
+++ b/smoketests/netadmin_smoketests.py
@@ -74,8 +74,10 @@ class AddressTests(base.UserSmokeTestCase):
groups = self.conn.get_all_security_groups(['default'])
for rule in groups[0].rules:
if (rule.ip_protocol == 'tcp' and
- rule.from_port <= 22 and rule.to_port >= 22):
+ int(rule.from_port) <= 22 and
+ int(rule.to_port) >= 22):
ssh_authorized = True
+ break
if not ssh_authorized:
self.conn.authorize_security_group('default',
ip_protocol='tcp',
--
cgit
From f7beae47ca505443eb86ea1a4fba6b47c1658755 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Thu, 24 Feb 2011 17:07:59 -0800
Subject: IPV6 FlatManager changes
---
nova/db/sqlalchemy/api.py | 11 ++--
.../versions/007_add_ipv6_flatmanager.py | 75 ++++++++++++++++++++++
nova/db/sqlalchemy/models.py | 3 +
nova/network/manager.py | 35 +++++++++-
nova/virt/interfaces.template | 16 +++--
nova/virt/libvirt_conn.py | 27 +++++---
6 files changed, 149 insertions(+), 18 deletions(-)
create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index d8751bef4..9bc59de60 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -833,10 +833,13 @@ def instance_get_fixed_address_v6(context, instance_id):
session = get_session()
with session.begin():
instance_ref = instance_get(context, instance_id, session=session)
- network_ref = network_get_by_instance(context, instance_id)
- prefix = network_ref.cidr_v6
- mac = instance_ref.mac_address
- return utils.to_global_ipv6(prefix, mac)
+ if 'nova.network.manager.FlatManager' == FLAGS.network_manager:
+ return instance_ref.fixed_ip['addressv6']
+ else:
+ network_ref = network_get_by_instance(context, instance_id)
+ prefix = network_ref.cidr_v6
+ mac = instance_ref.mac_address
+ return utils.to_global_ipv6(prefix, mac)
@require_context
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
new file mode 100644
index 000000000..2951cbc0a
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
@@ -0,0 +1,75 @@
+# Copyright 2010 OpenStack LLC.
+# All Rights Reserved.
+#
+# 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.
+
+from sqlalchemy import *
+from migrate import *
+
+from nova import log as logging
+
+
+meta = MetaData()
+
+
+# Table stub-definitions
+# Just for the ForeignKey and column creation to succeed, these are not the
+# actual definitions of instances or services.
+#
+networks = Table('networks', meta,
+ Column('id', Integer(), primary_key=True, nullable=False),
+ )
+
+fixed_ips = Table('fixed_ips', meta,
+ Column('id', Integer(), primary_key=True, nullable=False),
+ )
+
+#
+# New Tables
+#
+# None
+
+#
+# Tables to alter
+#
+# None
+
+#
+# Columns to add to existing tables
+#
+
+networks_gatewayv6 = Column(
+ 'gatewayv6',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False))
+
+networks_netmaskv6 = Column(
+ 'netmaskv6',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False))
+
+fixed_ips_addressv6 = Column(
+ 'addressv6',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False))
+
+
+def upgrade(migrate_engine):
+ # Upgrade operations go here. Don't create your own engine;
+ # bind migrate_engine to your metadata
+ meta.bind = migrate_engine
+
+ # Add columns to existing tables
+ networks.create_column(networks_gatewayv6)
+ networks.create_column(networks_netmaskv6)
+ fixed_ips.create_column(fixed_ips_addressv6)
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 1882efeba..4fa4d443c 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -385,6 +385,8 @@ class Network(BASE, NovaBase):
ra_server = Column(String(255))
+ gatewayv6 = Column(String(255))
+ netmaskv6 = Column(String(255))
netmask = Column(String(255))
bridge = Column(String(255))
gateway = Column(String(255))
@@ -425,6 +427,7 @@ class FixedIp(BASE, NovaBase):
__tablename__ = 'fixed_ips'
id = Column(Integer, primary_key=True)
address = Column(String(255))
+ addressv6 = Column(String(255))
network_id = Column(Integer, ForeignKey('networks.id'), nullable=True)
network = relationship(Network, backref=backref('fixed_ips'))
instance_id = Column(Integer, ForeignKey('instances.id'), nullable=True)
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 12a0c5018..61b5dc07f 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -361,9 +361,11 @@ class FlatManager(NetworkManager):
fixed_net = IPy.IP(cidr)
fixed_net_v6 = IPy.IP(cidr_v6)
significant_bits_v6 = 64
+ network_size_v6 = 1 << 64
count = 1
for index in range(num_networks):
start = index * network_size
+ start_v6 = index * network_size_v6
significant_bits = 32 - int(math.log(network_size, 2))
cidr = "%s/%s" % (fixed_net[start], significant_bits)
project_net = IPy.IP(cidr)
@@ -382,14 +384,45 @@ class FlatManager(NetworkManager):
count += 1
if(FLAGS.use_ipv6):
- cidr_v6 = "%s/%s" % (fixed_net_v6[0], significant_bits_v6)
+ cidr_v6 = "%s/%s" % (fixed_net_v6[start_v6],
+ significant_bits_v6)
net['cidr_v6'] = cidr_v6
+ project_net_v6 = IPy.IP(cidr_v6)
+ net['gatewayv6'] = str(project_net_v6[1])
+ net['netmaskv6'] = str(project_net_v6.prefixlen())
network_ref = self.db.network_create_safe(context, net)
if network_ref:
self._create_fixed_ips(context, network_ref['id'])
+ def _create_fixed_ips(self, context, network_id):
+ """Create all fixed ips for network."""
+ network_ref = self.db.network_get(context, network_id)
+ # NOTE(vish): Should these be properties of the network as opposed
+ # to properties of the manager class?
+ bottom_reserved = self._bottom_reserved_ips
+ top_reserved = self._top_reserved_ips
+ project_net = IPy.IP(network_ref['cidr'])
+
+ if(FLAGS.use_ipv6):
+ project_net_v6 = IPy.IP(network_ref['cidr_v6'])
+
+ num_ips = len(project_net)
+ addressv6 = None
+ for index in range(num_ips):
+ address = str(project_net[index])
+ if(FLAGS.use_ipv6):
+ addressv6 = str(project_net_v6[index])
+ if index < bottom_reserved or num_ips - index < top_reserved:
+ reserved = True
+ else:
+ reserved = False
+ self.db.fixed_ip_create(context, {'network_id': network_id,
+ 'address': address,
+ 'addressv6': addressv6,
+ 'reserved': reserved})
+
def get_network_host(self, context):
"""Get the network host for the current context."""
network_ref = self.db.network_get_by_bridge(context,
diff --git a/nova/virt/interfaces.template b/nova/virt/interfaces.template
index 87b92b84a..1db745f9f 100644
--- a/nova/virt/interfaces.template
+++ b/nova/virt/interfaces.template
@@ -8,10 +8,16 @@ iface lo inet loopback
# The primary network interface
auto eth0
iface eth0 inet static
- address %(address)s
- netmask %(netmask)s
- broadcast %(broadcast)s
- gateway %(gateway)s
- dns-nameservers %(dns)s
+ address ${address}
+ netmask ${netmask}
+ broadcast ${broadcast}
+ gateway ${gateway}
+ dns-nameservers ${dns}
+#if $use_ipv6
+iface eth0 inet6 static
+ address ${addressv6}
+ netmask ${netmaskv6}
+ gateway ${gatewayv6}
+#end if
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index 4e0fd106f..b7712f76e 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -146,6 +146,7 @@ class LibvirtConnection(object):
self.libvirt_uri = self.get_uri()
self.libvirt_xml = open(FLAGS.libvirt_xml_template).read()
+ self.interfaces_xml = open(FLAGS.injected_network_template).read()
self._wrapped_conn = None
self.read_only = read_only
@@ -628,17 +629,27 @@ class LibvirtConnection(object):
inst['id'])
if network_ref['injected']:
admin_context = context.get_admin_context()
- address = db.instance_get_fixed_address(admin_context, inst['id'])
+ address = db.instance_get_fixed_address(admin_context,
+ inst['id'])
+ addressv6 = db.instance_get_fixed_address_v6(admin_context,
+ inst['id'])
ra_server = network_ref['ra_server']
if not ra_server:
ra_server = "fd00::"
- with open(FLAGS.injected_network_template) as f:
- net = f.read() % {'address': address,
- 'netmask': network_ref['netmask'],
- 'gateway': network_ref['gateway'],
- 'broadcast': network_ref['broadcast'],
- 'dns': network_ref['dns'],
- 'ra_server': ra_server}
+
+ interfaces_info = {'address': address,
+ 'netmask': network_ref['netmask'],
+ 'gateway': network_ref['gateway'],
+ 'broadcast': network_ref['broadcast'],
+ 'dns': network_ref['dns'],
+ 'ra_server': ra_server,
+ 'addressv6': addressv6,
+ 'gatewayv6': network_ref['gatewayv6'],
+ 'netmaskv6': network_ref['netmaskv6'],
+ 'use_ipv6': FLAGS.use_ipv6}
+
+ net = str(Template(self.interfaces_xml,
+ searchList=[interfaces_info]))
if key or net:
inst_name = inst['name']
img_id = inst.image_id
--
cgit
From 498638ce36228615ecf8d98f99c0227f4f86963d Mon Sep 17 00:00:00 2001
From: Vishvananda Ishaya
Date: Thu, 24 Feb 2011 17:17:42 -0800
Subject: make smoketests run with nose
---
run_tests.py | 2 +
smoketests/admin_smoketests.py | 95 ----------
smoketests/netadmin_smoketests.py | 191 --------------------
smoketests/public_network_smoketests.py | 5 -
smoketests/run_tests.py | 297 ++++++++++++++++++++++++++++++++
smoketests/sysadmin_smoketests.py | 295 -------------------------------
smoketests/test_admin.py | 91 ++++++++++
smoketests/test_netadmin.py | 184 ++++++++++++++++++++
smoketests/test_sysadmin.py | 287 ++++++++++++++++++++++++++++++
9 files changed, 861 insertions(+), 586 deletions(-)
delete mode 100644 smoketests/admin_smoketests.py
delete mode 100644 smoketests/netadmin_smoketests.py
create mode 100644 smoketests/run_tests.py
delete mode 100644 smoketests/sysadmin_smoketests.py
create mode 100644 smoketests/test_admin.py
create mode 100644 smoketests/test_netadmin.py
create mode 100644 smoketests/test_sysadmin.py
diff --git a/run_tests.py b/run_tests.py
index 3c8d410e1..d5d8acd16 100644
--- a/run_tests.py
+++ b/run_tests.py
@@ -60,6 +60,8 @@ import os
import unittest
import sys
+gettext.install('nova', unicode=1)
+
from nose import config
from nose import core
from nose import result
diff --git a/smoketests/admin_smoketests.py b/smoketests/admin_smoketests.py
deleted file mode 100644
index cb3010965..000000000
--- a/smoketests/admin_smoketests.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# 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 os
-import random
-import sys
-import unittest
-import zipfile
-
-# If ../nova/__init__.py exists, add ../ to Python search path, so that
-# it will override what happens to be installed in /usr/(local/)lib/python...
-possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
- os.pardir,
- os.pardir))
-if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
- sys.path.insert(0, possible_topdir)
-
-from nova import adminclient
-from smoketests import flags
-from smoketests import base
-
-
-FLAGS = flags.FLAGS
-
-# TODO(devamcar): Use random tempfile
-ZIP_FILENAME = '/tmp/nova-me-x509.zip'
-
-TEST_PREFIX = 'test%s' % int(random.random() * 1000000)
-TEST_USERNAME = '%suser' % TEST_PREFIX
-TEST_PROJECTNAME = '%sproject' % TEST_PREFIX
-
-
-class AdminSmokeTestCase(base.SmokeTestCase):
- def setUp(self):
- self.admin = adminclient.NovaAdminClient(
- access_key=os.getenv('EC2_ACCESS_KEY'),
- secret_key=os.getenv('EC2_SECRET_KEY'),
- clc_url=os.getenv('EC2_URL'),
- region=FLAGS.region)
-
-
-class UserTests(AdminSmokeTestCase):
- """ Test admin credentials and user creation. """
-
- def test_001_admin_can_connect(self):
- conn = self.admin.connection_for('admin', 'admin')
- self.assert_(conn)
-
- def test_002_admin_can_create_user(self):
- user = self.admin.create_user(TEST_USERNAME)
- self.assertEqual(user.username, TEST_USERNAME)
-
- def test_003_admin_can_create_project(self):
- project = self.admin.create_project(TEST_PROJECTNAME,
- TEST_USERNAME)
- self.assertEqual(project.projectname, TEST_PROJECTNAME)
-
- def test_004_user_can_download_credentials(self):
- buf = self.admin.get_zip(TEST_USERNAME, TEST_PROJECTNAME)
- output = open(ZIP_FILENAME, 'w')
- output.write(buf)
- output.close()
-
- zip = zipfile.ZipFile(ZIP_FILENAME, 'a', zipfile.ZIP_DEFLATED)
- bad = zip.testzip()
- zip.close()
-
- self.failIf(bad)
-
- def test_999_tearDown(self):
- self.admin.delete_project(TEST_PROJECTNAME)
- self.admin.delete_user(TEST_USERNAME)
- try:
- os.remove(ZIP_FILENAME)
- except:
- pass
-
-if __name__ == "__main__":
- suites = {'user': unittest.makeSuite(UserTests)}
- sys.exit(base.run_tests(suites))
diff --git a/smoketests/netadmin_smoketests.py b/smoketests/netadmin_smoketests.py
deleted file mode 100644
index 54432242c..000000000
--- a/smoketests/netadmin_smoketests.py
+++ /dev/null
@@ -1,191 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# 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 commands
-import os
-import random
-import sys
-import time
-import unittest
-
-# If ../nova/__init__.py exists, add ../ to Python search path, so that
-# it will override what happens to be installed in /usr/(local/)lib/python...
-possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
- os.pardir,
- os.pardir))
-if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
- sys.path.insert(0, possible_topdir)
-
-from smoketests import flags
-from smoketests import base
-
-
-FLAGS = flags.FLAGS
-
-TEST_PREFIX = 'test%s' % int(random.random() * 1000000)
-TEST_BUCKET = '%s_bucket' % TEST_PREFIX
-TEST_KEY = '%s_key' % TEST_PREFIX
-TEST_GROUP = '%s_group' % TEST_PREFIX
-
-
-class AddressTests(base.UserSmokeTestCase):
- def test_000_setUp(self):
- self.create_key_pair(self.conn, TEST_KEY)
- reservation = self.conn.run_instances(FLAGS.test_image,
- instance_type='m1.tiny',
- key_name=TEST_KEY)
- self.data['instance'] = reservation.instances[0]
- if not self.wait_for_running(self.data['instance']):
- self.fail('instance failed to start')
- self.data['instance'].update()
- if not self.wait_for_ping(self.data['instance'].private_dns_name):
- self.fail('could not ping instance')
- if not self.wait_for_ssh(self.data['instance'].private_dns_name,
- TEST_KEY):
- self.fail('could not ssh to instance')
-
- def test_001_can_allocate_floating_ip(self):
- result = self.conn.allocate_address()
- self.assertTrue(hasattr(result, 'public_ip'))
- self.data['public_ip'] = result.public_ip
-
- def test_002_can_associate_ip_with_instance(self):
- result = self.conn.associate_address(self.data['instance'].id,
- self.data['public_ip'])
- self.assertTrue(result)
-
- def test_003_can_ssh_with_public_ip(self):
- ssh_authorized = False
- groups = self.conn.get_all_security_groups(['default'])
- for rule in groups[0].rules:
- if (rule.ip_protocol == 'tcp' and
- int(rule.from_port) <= 22 and
- int(rule.to_port) >= 22):
- ssh_authorized = True
- break
- if not ssh_authorized:
- self.conn.authorize_security_group('default',
- ip_protocol='tcp',
- from_port=22,
- to_port=22)
- try:
- if not self.wait_for_ssh(self.data['public_ip'], TEST_KEY):
- self.fail('could not ssh to public ip')
- finally:
- if not ssh_authorized:
- self.conn.revoke_security_group('default',
- ip_protocol='tcp',
- from_port=22,
- to_port=22)
-
- def test_004_can_disassociate_ip_from_instance(self):
- result = self.conn.disassociate_address(self.data['public_ip'])
- self.assertTrue(result)
-
- def test_005_can_deallocate_floating_ip(self):
- result = self.conn.release_address(self.data['public_ip'])
- self.assertTrue(result)
-
- def test_999_tearDown(self):
- self.delete_key_pair(self.conn, TEST_KEY)
- self.conn.terminate_instances([self.data['instance'].id])
-
-
-class SecurityGroupTests(base.UserSmokeTestCase):
-
- def __public_instance_is_accessible(self):
- id_url = "latest/meta-data/instance-id"
- options = "-s --max-time 1"
- command = "curl %s %s/%s" % (options, self.data['public_ip'], id_url)
- instance_id = commands.getoutput(command).strip()
- if not instance_id:
- return False
- if instance_id != self.data['instance'].id:
- raise Exception("Wrong instance id")
- return True
-
- def test_001_can_create_security_group(self):
- self.conn.create_security_group(TEST_GROUP, description='test')
-
- groups = self.conn.get_all_security_groups()
- self.assertTrue(TEST_GROUP in [group.name for group in groups])
-
- def test_002_can_launch_instance_in_security_group(self):
- with open("proxy.sh") as f:
- user_data = f.read()
- self.create_key_pair(self.conn, TEST_KEY)
- reservation = self.conn.run_instances(FLAGS.test_image,
- key_name=TEST_KEY,
- security_groups=[TEST_GROUP],
- user_data=user_data,
- instance_type='m1.tiny')
-
- self.data['instance'] = reservation.instances[0]
- if not self.wait_for_running(self.data['instance']):
- self.fail('instance failed to start')
- self.data['instance'].update()
-
- def test_003_can_authorize_security_group_ingress(self):
- self.assertTrue(self.conn.authorize_security_group(TEST_GROUP,
- ip_protocol='tcp',
- from_port=80,
- to_port=80))
-
- def test_004_can_access_metadata_over_public_ip(self):
- result = self.conn.allocate_address()
- self.assertTrue(hasattr(result, 'public_ip'))
- self.data['public_ip'] = result.public_ip
-
- result = self.conn.associate_address(self.data['instance'].id,
- self.data['public_ip'])
- start_time = time.time()
- try:
- while not self.__public_instance_is_accessible():
- # 1 minute to launch
- if time.time() - start_time > 60:
- raise Exception("Timeout")
- time.sleep(1)
- finally:
- result = self.conn.disassociate_address(self.data['public_ip'])
-
- def test_005_can_revoke_security_group_ingress(self):
- self.assertTrue(self.conn.revoke_security_group(TEST_GROUP,
- ip_protocol='tcp',
- from_port=80,
- to_port=80))
- start_time = time.time()
- while self.__public_instance_is_accessible():
- # 1 minute to teardown
- if time.time() - start_time > 60:
- raise Exception("Timeout")
- time.sleep(1)
-
- def test_999_tearDown(self):
- self.conn.delete_key_pair(TEST_KEY)
- self.conn.delete_security_group(TEST_GROUP)
- groups = self.conn.get_all_security_groups()
- self.assertFalse(TEST_GROUP in [group.name for group in groups])
- self.conn.terminate_instances([self.data['instance'].id])
- self.assertTrue(self.conn.release_address(self.data['public_ip']))
-
-
-if __name__ == "__main__":
- suites = {'address': unittest.makeSuite(AddressTests),
- 'security_group': unittest.makeSuite(SecurityGroupTests)
- }
- sys.exit(base.run_tests(suites))
diff --git a/smoketests/public_network_smoketests.py b/smoketests/public_network_smoketests.py
index 5a4c67642..aa1fc548f 100644
--- a/smoketests/public_network_smoketests.py
+++ b/smoketests/public_network_smoketests.py
@@ -19,7 +19,6 @@
import commands
import os
import random
-import socket
import sys
import time
import unittest
@@ -181,7 +180,3 @@ class InstanceTestsFromPublic(base.UserSmokeTestCase):
self.conn.delete_security_group(security_group_name)
if 'instance_id' in self.data:
self.conn.terminate_instances([self.data['instance_id']])
-
-if __name__ == "__main__":
- suites = {'instance': unittest.makeSuite(InstanceTestsFromPublic)}
- sys.exit(base.run_tests(suites))
diff --git a/smoketests/run_tests.py b/smoketests/run_tests.py
new file mode 100644
index 000000000..4f06f0f2b
--- /dev/null
+++ b/smoketests/run_tests.py
@@ -0,0 +1,297 @@
+#!/usr/bin/env python
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# 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.
+
+# Colorizer Code is borrowed from Twisted:
+# Copyright (c) 2001-2010 Twisted Matrix Laboratories.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"""Unittest runner for Nova.
+
+To run all tests
+ python run_tests.py
+
+To run a single test:
+ python run_tests.py test_compute:ComputeTestCase.test_run_terminate
+
+To run a single test module:
+ python run_tests.py test_compute
+
+ or
+
+ python run_tests.py api.test_wsgi
+
+"""
+
+import gettext
+import os
+import unittest
+import sys
+
+gettext.install('nova', unicode=1)
+
+from nose import config
+from nose import core
+from nose import result
+
+
+class _AnsiColorizer(object):
+ """
+ A colorizer is an object that loosely wraps around a stream, allowing
+ callers to write text to the stream in a particular color.
+
+ Colorizer classes must implement C{supported()} and C{write(text, color)}.
+ """
+ _colors = dict(black=30, red=31, green=32, yellow=33,
+ blue=34, magenta=35, cyan=36, white=37)
+
+ def __init__(self, stream):
+ self.stream = stream
+
+ def supported(cls, stream=sys.stdout):
+ """
+ A class method that returns True if the current platform supports
+ coloring terminal output using this method. Returns False otherwise.
+ """
+ if not stream.isatty():
+ return False # auto color only on TTYs
+ try:
+ import curses
+ except ImportError:
+ return False
+ else:
+ try:
+ try:
+ return curses.tigetnum("colors") > 2
+ except curses.error:
+ curses.setupterm()
+ return curses.tigetnum("colors") > 2
+ except:
+ raise
+ # guess false in case of error
+ return False
+ supported = classmethod(supported)
+
+ def write(self, text, color):
+ """
+ Write the given text to the stream in the given color.
+
+ @param text: Text to be written to the stream.
+
+ @param color: A string label for a color. e.g. 'red', 'white'.
+ """
+ color = self._colors[color]
+ self.stream.write('\x1b[%s;1m%s\x1b[0m' % (color, text))
+
+
+class _Win32Colorizer(object):
+ """
+ See _AnsiColorizer docstring.
+ """
+ def __init__(self, stream):
+ from win32console import GetStdHandle, STD_OUT_HANDLE, \
+ FOREGROUND_RED, FOREGROUND_BLUE, FOREGROUND_GREEN, \
+ FOREGROUND_INTENSITY
+ red, green, blue, bold = (FOREGROUND_RED, FOREGROUND_GREEN,
+ FOREGROUND_BLUE, FOREGROUND_INTENSITY)
+ self.stream = stream
+ self.screenBuffer = GetStdHandle(STD_OUT_HANDLE)
+ self._colors = {
+ 'normal': red | green | blue,
+ 'red': red | bold,
+ 'green': green | bold,
+ 'blue': blue | bold,
+ 'yellow': red | green | bold,
+ 'magenta': red | blue | bold,
+ 'cyan': green | blue | bold,
+ 'white': red | green | blue | bold
+ }
+
+ def supported(cls, stream=sys.stdout):
+ try:
+ import win32console
+ screenBuffer = win32console.GetStdHandle(
+ win32console.STD_OUT_HANDLE)
+ except ImportError:
+ return False
+ import pywintypes
+ try:
+ screenBuffer.SetConsoleTextAttribute(
+ win32console.FOREGROUND_RED |
+ win32console.FOREGROUND_GREEN |
+ win32console.FOREGROUND_BLUE)
+ except pywintypes.error:
+ return False
+ else:
+ return True
+ supported = classmethod(supported)
+
+ def write(self, text, color):
+ color = self._colors[color]
+ self.screenBuffer.SetConsoleTextAttribute(color)
+ self.stream.write(text)
+ self.screenBuffer.SetConsoleTextAttribute(self._colors['normal'])
+
+
+class _NullColorizer(object):
+ """
+ See _AnsiColorizer docstring.
+ """
+ def __init__(self, stream):
+ self.stream = stream
+
+ def supported(cls, stream=sys.stdout):
+ return True
+ supported = classmethod(supported)
+
+ def write(self, text, color):
+ self.stream.write(text)
+
+
+class NovaTestResult(result.TextTestResult):
+ def __init__(self, *args, **kw):
+ result.TextTestResult.__init__(self, *args, **kw)
+ self._last_case = None
+ self.colorizer = None
+ # NOTE(vish): reset stdout for the terminal check
+ stdout = sys.stdout
+ sys.stdout = sys.__stdout__
+ for colorizer in [_Win32Colorizer, _AnsiColorizer, _NullColorizer]:
+ if colorizer.supported():
+ self.colorizer = colorizer(self.stream)
+ break
+ sys.stdout = stdout
+
+ def getDescription(self, test):
+ return str(test)
+
+ # NOTE(vish): copied from unittest with edit to add color
+ def addSuccess(self, test):
+ unittest.TestResult.addSuccess(self, test)
+ if self.showAll:
+ self.colorizer.write("OK", 'green')
+ self.stream.writeln()
+ elif self.dots:
+ self.stream.write('.')
+ self.stream.flush()
+
+ # NOTE(vish): copied from unittest with edit to add color
+ def addFailure(self, test, err):
+ unittest.TestResult.addFailure(self, test, err)
+ if self.showAll:
+ self.colorizer.write("FAIL", 'red')
+ self.stream.writeln()
+ elif self.dots:
+ self.stream.write('F')
+ self.stream.flush()
+
+ # NOTE(vish): copied from nose with edit to add color
+ def addError(self, test, err):
+ """Overrides normal addError to add support for
+ errorClasses. If the exception is a registered class, the
+ error will be added to the list for that class, not errors.
+ """
+ stream = getattr(self, 'stream', None)
+ ec, ev, tb = err
+ try:
+ exc_info = self._exc_info_to_string(err, test)
+ except TypeError:
+ # 2.3 compat
+ exc_info = self._exc_info_to_string(err)
+ for cls, (storage, label, isfail) in self.errorClasses.items():
+ if result.isclass(ec) and issubclass(ec, cls):
+ if isfail:
+ test.passed = False
+ storage.append((test, exc_info))
+ # Might get patched into a streamless result
+ if stream is not None:
+ if self.showAll:
+ message = [label]
+ detail = result._exception_detail(err[1])
+ if detail:
+ message.append(detail)
+ stream.writeln(": ".join(message))
+ elif self.dots:
+ stream.write(label[:1])
+ return
+ self.errors.append((test, exc_info))
+ test.passed = False
+ if stream is not None:
+ if self.showAll:
+ self.colorizer.write("ERROR", 'red')
+ self.stream.writeln()
+ elif self.dots:
+ stream.write('E')
+
+ def startTest(self, test):
+ unittest.TestResult.startTest(self, test)
+ current_case = test.test.__class__.__name__
+
+ if self.showAll:
+ if current_case != self._last_case:
+ self.stream.writeln(current_case)
+ self._last_case = current_case
+
+ self.stream.write(
+ ' %s' % str(test.test._testMethodName).ljust(60))
+ self.stream.flush()
+
+
+class NovaTestRunner(core.TextTestRunner):
+ def _makeResult(self):
+ return NovaTestResult(self.stream,
+ self.descriptions,
+ self.verbosity,
+ self.config)
+
+
+if __name__ == '__main__':
+ if not os.getenv('EC2_ACCESS_KEY'):
+ print _('Missing EC2 environment variables. Please ' \
+ 'source the appropriate novarc file before ' \
+ 'running this test.')
+ sys.exit(1)
+
+ testdir = os.path.abspath("./")
+ c = config.Config(stream=sys.stdout,
+ env=os.environ,
+ verbosity=3,
+ workingDir=testdir,
+ plugins=core.DefaultPluginManager())
+
+ runner = NovaTestRunner(stream=c.stream,
+ verbosity=c.verbosity,
+ config=c)
+ sys.exit(not core.run(config=c, testRunner=runner, argv=sys.argv))
diff --git a/smoketests/sysadmin_smoketests.py b/smoketests/sysadmin_smoketests.py
deleted file mode 100644
index 3b267bc65..000000000
--- a/smoketests/sysadmin_smoketests.py
+++ /dev/null
@@ -1,295 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# 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 commands
-import os
-import random
-import sys
-import time
-import unittest
-
-# If ../nova/__init__.py exists, add ../ to Python search path, so that
-# it will override what happens to be installed in /usr/(local/)lib/python...
-possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
- os.pardir,
- os.pardir))
-if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
- sys.path.insert(0, possible_topdir)
-
-from smoketests import flags
-from smoketests import base
-
-
-
-FLAGS = flags.FLAGS
-flags.DEFINE_string('bundle_kernel', 'openwrt-x86-vmlinuz',
- 'Local kernel file to use for bundling tests')
-flags.DEFINE_string('bundle_image', 'openwrt-x86-ext2.image',
- 'Local image file to use for bundling tests')
-
-TEST_PREFIX = 'test%s' % int(random.random() * 1000000)
-TEST_BUCKET = '%s_bucket' % TEST_PREFIX
-TEST_KEY = '%s_key' % TEST_PREFIX
-TEST_GROUP = '%s_group' % TEST_PREFIX
-class ImageTests(base.UserSmokeTestCase):
- def test_001_can_bundle_image(self):
- self.assertTrue(self.bundle_image(FLAGS.bundle_image))
-
- def test_002_can_upload_image(self):
- self.assertTrue(self.upload_image(TEST_BUCKET, FLAGS.bundle_image))
-
- def test_003_can_register_image(self):
- image_id = self.conn.register_image('%s/%s.manifest.xml' %
- (TEST_BUCKET, FLAGS.bundle_image))
- self.assert_(image_id is not None)
- self.data['image_id'] = image_id
-
- def test_004_can_bundle_kernel(self):
- self.assertTrue(self.bundle_image(FLAGS.bundle_kernel, kernel=True))
-
- def test_005_can_upload_kernel(self):
- self.assertTrue(self.upload_image(TEST_BUCKET, FLAGS.bundle_kernel))
-
- def test_006_can_register_kernel(self):
- kernel_id = self.conn.register_image('%s/%s.manifest.xml' %
- (TEST_BUCKET, FLAGS.bundle_kernel))
- self.assert_(kernel_id is not None)
- self.data['kernel_id'] = kernel_id
-
- def test_007_images_are_available_within_10_seconds(self):
- for i in xrange(10):
- image = self.conn.get_image(self.data['image_id'])
- if image and image.state == 'available':
- break
- time.sleep(1)
- else:
- self.assert_(False) # wasn't available within 10 seconds
- self.assert_(image.type == 'machine')
-
- for i in xrange(10):
- kernel = self.conn.get_image(self.data['kernel_id'])
- if kernel and kernel.state == 'available':
- break
- time.sleep(1)
- else:
- self.assert_(False) # wasn't available within 10 seconds
- self.assert_(kernel.type == 'kernel')
-
- def test_008_can_describe_image_attribute(self):
- attrs = self.conn.get_image_attribute(self.data['image_id'],
- 'launchPermission')
- self.assert_(attrs.name, 'launch_permission')
-
- def test_009_can_modify_image_launch_permission(self):
- self.conn.modify_image_attribute(image_id=self.data['image_id'],
- operation='add',
- attribute='launchPermission',
- groups='all')
- image = self.conn.get_image(self.data['image_id'])
- self.assertEqual(image.id, self.data['image_id'])
-
- def test_010_can_see_launch_permission(self):
- attrs = self.conn.get_image_attribute(self.data['image_id'],
- 'launchPermission')
- self.assert_(attrs.name, 'launch_permission')
- self.assert_(attrs.attrs['groups'][0], 'all')
-
- def test_011_user_can_deregister_kernel(self):
- self.assertTrue(self.conn.deregister_image(self.data['kernel_id']))
-
- def test_012_can_deregister_image(self):
- self.assertTrue(self.conn.deregister_image(self.data['image_id']))
-
- def test_013_can_delete_bundle(self):
- self.assertTrue(self.delete_bundle_bucket(TEST_BUCKET))
-
-
-class InstanceTests(base.UserSmokeTestCase):
- def test_001_can_create_keypair(self):
- key = self.create_key_pair(self.conn, TEST_KEY)
- self.assertEqual(key.name, TEST_KEY)
-
- def test_002_can_create_instance_with_keypair(self):
- reservation = self.conn.run_instances(FLAGS.test_image,
- key_name=TEST_KEY,
- instance_type='m1.tiny')
- self.assertEqual(len(reservation.instances), 1)
- self.data['instance'] = reservation.instances[0]
-
- def test_003_instance_runs_within_60_seconds(self):
- instance = self.data['instance']
- # allow 60 seconds to exit pending with IP
- if not self.wait_for_running(self.data['instance']):
- self.fail('instance failed to start')
- self.data['instance'].update()
- ip = self.data['instance'].private_dns_name
- self.failIf(ip == '0.0.0.0')
- if FLAGS.use_ipv6:
- ipv6 = self.data['instance'].dns_name_v6
- self.failIf(ipv6 is None)
-
- def test_004_can_ping_private_ip(self):
- if not self.wait_for_ping(self.data['instance'].private_dns_name):
- self.fail('could not ping instance')
-
- if FLAGS.use_ipv6:
- if not self.wait_for_ping(self.data['instance'].ip_v6, "ping6"):
- self.fail('could not ping instance v6')
-
- def test_005_can_ssh_to_private_ip(self):
- if not self.wait_for_ssh(self.data['instance'].private_dns_name,
- TEST_KEY):
- self.fail('could not ssh to instance')
-
- if FLAGS.use_ipv6:
- if not self.wait_for_ssh(self.data['instance'].ip_v6,
- TEST_KEY):
- self.fail('could not ssh to instance v6')
-
- def test_999_tearDown(self):
- self.delete_key_pair(self.conn, TEST_KEY)
- self.conn.terminate_instances([self.data['instance'].id])
-
-
-class VolumeTests(base.UserSmokeTestCase):
- def setUp(self):
- super(VolumeTests, self).setUp()
- self.device = '/dev/vdb'
-
- def test_000_setUp(self):
- self.create_key_pair(self.conn, TEST_KEY)
- reservation = self.conn.run_instances(FLAGS.test_image,
- instance_type='m1.tiny',
- key_name=TEST_KEY)
- self.data['instance'] = reservation.instances[0]
- if not self.wait_for_running(self.data['instance']):
- self.fail('instance failed to start')
- self.data['instance'].update()
- if not self.wait_for_ping(self.data['instance'].private_dns_name):
- self.fail('could not ping instance')
- if not self.wait_for_ssh(self.data['instance'].private_dns_name,
- TEST_KEY):
- self.fail('could not ssh to instance')
-
- def test_001_can_create_volume(self):
- volume = self.conn.create_volume(1, 'nova')
- self.assertEqual(volume.size, 1)
- self.data['volume'] = volume
- # Give network time to find volume.
- time.sleep(5)
-
- def test_002_can_attach_volume(self):
- volume = self.data['volume']
-
- for x in xrange(10):
- volume.update()
- if volume.status.startswith('available'):
- break
- time.sleep(1)
- else:
- self.fail('cannot attach volume with state %s' % volume.status)
-
- # Give volume some time to be ready.
- time.sleep(5)
- volume.attach(self.data['instance'].id, self.device)
-
- # wait
- for x in xrange(10):
- volume.update()
- if volume.status.startswith('in-use'):
- break
- time.sleep(1)
- else:
- self.fail('volume never got to in use')
-
- self.assertTrue(volume.status.startswith('in-use'))
-
- # Give instance time to recognize volume.
- time.sleep(5)
-
- def test_003_can_mount_volume(self):
- ip = self.data['instance'].private_dns_name
- conn = self.connect_ssh(ip, TEST_KEY)
- # NOTE(vish): this will create an dev for images that don't have
- # udev rules
- stdin, stdout, stderr = conn.exec_command(
- 'grep %s /proc/partitions | '
- '`awk \'{print "mknod /dev/"\\$4" b "\\$1" "\\$2}\'`'
- % self.device.rpartition('/')[2])
- exec_list = []
- exec_list.append('mkdir -p /mnt/vol')
- exec_list.append('/sbin/mke2fs %s' % self.device)
- exec_list.append('mount %s /mnt/vol' % self.device)
- exec_list.append('echo success')
- stdin, stdout, stderr = conn.exec_command(' && '.join(exec_list))
- out = stdout.read()
- conn.close()
- if not out.strip().endswith('success'):
- self.fail('Unable to mount: %s %s' % (out, stderr.read()))
-
- def test_004_can_write_to_volume(self):
- ip = self.data['instance'].private_dns_name
- conn = self.connect_ssh(ip, TEST_KEY)
- # FIXME(devcamcar): This doesn't fail if the volume hasn't been mounted
- stdin, stdout, stderr = conn.exec_command(
- 'echo hello > /mnt/vol/test.txt')
- err = stderr.read()
- conn.close()
- if len(err) > 0:
- self.fail('Unable to write to mount: %s' % (err))
-
- def test_005_volume_is_correct_size(self):
- ip = self.data['instance'].private_dns_name
- conn = self.connect_ssh(ip, TEST_KEY)
- stdin, stdout, stderr = conn.exec_command(
- "df -h | grep %s | awk {'print $2'}" % self.device)
- out = stdout.read()
- conn.close()
- if not out.strip() == '1007.9M':
- self.fail('Volume is not the right size: %s %s' %
- (out, stderr.read()))
-
- def test_006_me_can_umount_volume(self):
- ip = self.data['instance'].private_dns_name
- conn = self.connect_ssh(ip, TEST_KEY)
- stdin, stdout, stderr = conn.exec_command('umount /mnt/vol')
- err = stderr.read()
- conn.close()
- if len(err) > 0:
- self.fail('Unable to unmount: %s' % (err))
-
- def test_007_me_can_detach_volume(self):
- result = self.conn.detach_volume(volume_id=self.data['volume'].id)
- self.assertTrue(result)
- time.sleep(5)
-
- def test_008_me_can_delete_volume(self):
- result = self.conn.delete_volume(self.data['volume'].id)
- self.assertTrue(result)
-
- def test_999_tearDown(self):
- self.conn.terminate_instances([self.data['instance'].id])
- self.conn.delete_key_pair(TEST_KEY)
-
-
-if __name__ == "__main__":
- suites = {'image': unittest.makeSuite(ImageTests),
- 'instance': unittest.makeSuite(InstanceTests),
- 'volume': unittest.makeSuite(VolumeTests)
- }
- sys.exit(base.run_tests(suites))
diff --git a/smoketests/test_admin.py b/smoketests/test_admin.py
new file mode 100644
index 000000000..46e5b2233
--- /dev/null
+++ b/smoketests/test_admin.py
@@ -0,0 +1,91 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# 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 os
+import random
+import sys
+import unittest
+import zipfile
+
+# If ../nova/__init__.py exists, add ../ to Python search path, so that
+# it will override what happens to be installed in /usr/(local/)lib/python...
+possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
+ os.pardir,
+ os.pardir))
+if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
+ sys.path.insert(0, possible_topdir)
+
+from nova import adminclient
+from smoketests import flags
+from smoketests import base
+
+
+FLAGS = flags.FLAGS
+
+# TODO(devamcar): Use random tempfile
+ZIP_FILENAME = '/tmp/nova-me-x509.zip'
+
+TEST_PREFIX = 'test%s' % int(random.random() * 1000000)
+TEST_USERNAME = '%suser' % TEST_PREFIX
+TEST_PROJECTNAME = '%sproject' % TEST_PREFIX
+
+
+class AdminSmokeTestCase(base.SmokeTestCase):
+ def setUp(self):
+ self.admin = adminclient.NovaAdminClient(
+ access_key=os.getenv('EC2_ACCESS_KEY'),
+ secret_key=os.getenv('EC2_SECRET_KEY'),
+ clc_url=os.getenv('EC2_URL'),
+ region=FLAGS.region)
+
+
+class UserTests(AdminSmokeTestCase):
+ """ Test admin credentials and user creation. """
+
+ def test_001_admin_can_connect(self):
+ conn = self.admin.connection_for('admin', 'admin')
+ self.assert_(conn)
+
+ def test_002_admin_can_create_user(self):
+ user = self.admin.create_user(TEST_USERNAME)
+ self.assertEqual(user.username, TEST_USERNAME)
+
+ def test_003_admin_can_create_project(self):
+ project = self.admin.create_project(TEST_PROJECTNAME,
+ TEST_USERNAME)
+ self.assertEqual(project.projectname, TEST_PROJECTNAME)
+
+ def test_004_user_can_download_credentials(self):
+ buf = self.admin.get_zip(TEST_USERNAME, TEST_PROJECTNAME)
+ output = open(ZIP_FILENAME, 'w')
+ output.write(buf)
+ output.close()
+
+ zip = zipfile.ZipFile(ZIP_FILENAME, 'a', zipfile.ZIP_DEFLATED)
+ bad = zip.testzip()
+ zip.close()
+
+ self.failIf(bad)
+
+ def test_999_tearDown(self):
+ self.admin.delete_project(TEST_PROJECTNAME)
+ self.admin.delete_user(TEST_USERNAME)
+ try:
+ os.remove(ZIP_FILENAME)
+ except:
+ pass
diff --git a/smoketests/test_netadmin.py b/smoketests/test_netadmin.py
new file mode 100644
index 000000000..4f033e4bc
--- /dev/null
+++ b/smoketests/test_netadmin.py
@@ -0,0 +1,184 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# 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 commands
+import os
+import random
+import sys
+import time
+import unittest
+
+# If ../nova/__init__.py exists, add ../ to Python search path, so that
+# it will override what happens to be installed in /usr/(local/)lib/python...
+possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
+ os.pardir,
+ os.pardir))
+if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
+ sys.path.insert(0, possible_topdir)
+
+from smoketests import flags
+from smoketests import base
+
+
+FLAGS = flags.FLAGS
+
+TEST_PREFIX = 'test%s' % int(random.random() * 1000000)
+TEST_BUCKET = '%s_bucket' % TEST_PREFIX
+TEST_KEY = '%s_key' % TEST_PREFIX
+TEST_GROUP = '%s_group' % TEST_PREFIX
+
+
+class AddressTests(base.UserSmokeTestCase):
+ def test_000_setUp(self):
+ self.create_key_pair(self.conn, TEST_KEY)
+ reservation = self.conn.run_instances(FLAGS.test_image,
+ instance_type='m1.tiny',
+ key_name=TEST_KEY)
+ self.data['instance'] = reservation.instances[0]
+ if not self.wait_for_running(self.data['instance']):
+ self.fail('instance failed to start')
+ self.data['instance'].update()
+ if not self.wait_for_ping(self.data['instance'].private_dns_name):
+ self.fail('could not ping instance')
+ if not self.wait_for_ssh(self.data['instance'].private_dns_name,
+ TEST_KEY):
+ self.fail('could not ssh to instance')
+
+ def test_001_can_allocate_floating_ip(self):
+ result = self.conn.allocate_address()
+ self.assertTrue(hasattr(result, 'public_ip'))
+ self.data['public_ip'] = result.public_ip
+
+ def test_002_can_associate_ip_with_instance(self):
+ result = self.conn.associate_address(self.data['instance'].id,
+ self.data['public_ip'])
+ self.assertTrue(result)
+
+ def test_003_can_ssh_with_public_ip(self):
+ ssh_authorized = False
+ groups = self.conn.get_all_security_groups(['default'])
+ for rule in groups[0].rules:
+ if (rule.ip_protocol == 'tcp' and
+ int(rule.from_port) <= 22 and
+ int(rule.to_port) >= 22):
+ ssh_authorized = True
+ break
+ if not ssh_authorized:
+ self.conn.authorize_security_group('default',
+ ip_protocol='tcp',
+ from_port=22,
+ to_port=22)
+ try:
+ if not self.wait_for_ssh(self.data['public_ip'], TEST_KEY):
+ self.fail('could not ssh to public ip')
+ finally:
+ if not ssh_authorized:
+ self.conn.revoke_security_group('default',
+ ip_protocol='tcp',
+ from_port=22,
+ to_port=22)
+
+ def test_004_can_disassociate_ip_from_instance(self):
+ result = self.conn.disassociate_address(self.data['public_ip'])
+ self.assertTrue(result)
+
+ def test_005_can_deallocate_floating_ip(self):
+ result = self.conn.release_address(self.data['public_ip'])
+ self.assertTrue(result)
+
+ def test_999_tearDown(self):
+ self.delete_key_pair(self.conn, TEST_KEY)
+ self.conn.terminate_instances([self.data['instance'].id])
+
+
+class SecurityGroupTests(base.UserSmokeTestCase):
+
+ def __public_instance_is_accessible(self):
+ id_url = "latest/meta-data/instance-id"
+ options = "-s --max-time 1"
+ command = "curl %s %s/%s" % (options, self.data['public_ip'], id_url)
+ instance_id = commands.getoutput(command).strip()
+ if not instance_id:
+ return False
+ if instance_id != self.data['instance'].id:
+ raise Exception("Wrong instance id")
+ return True
+
+ def test_001_can_create_security_group(self):
+ self.conn.create_security_group(TEST_GROUP, description='test')
+
+ groups = self.conn.get_all_security_groups()
+ self.assertTrue(TEST_GROUP in [group.name for group in groups])
+
+ def test_002_can_launch_instance_in_security_group(self):
+ with open("proxy.sh") as f:
+ user_data = f.read()
+ self.create_key_pair(self.conn, TEST_KEY)
+ reservation = self.conn.run_instances(FLAGS.test_image,
+ key_name=TEST_KEY,
+ security_groups=[TEST_GROUP],
+ user_data=user_data,
+ instance_type='m1.tiny')
+
+ self.data['instance'] = reservation.instances[0]
+ if not self.wait_for_running(self.data['instance']):
+ self.fail('instance failed to start')
+ self.data['instance'].update()
+
+ def test_003_can_authorize_security_group_ingress(self):
+ self.assertTrue(self.conn.authorize_security_group(TEST_GROUP,
+ ip_protocol='tcp',
+ from_port=80,
+ to_port=80))
+
+ def test_004_can_access_metadata_over_public_ip(self):
+ result = self.conn.allocate_address()
+ self.assertTrue(hasattr(result, 'public_ip'))
+ self.data['public_ip'] = result.public_ip
+
+ result = self.conn.associate_address(self.data['instance'].id,
+ self.data['public_ip'])
+ start_time = time.time()
+ try:
+ while not self.__public_instance_is_accessible():
+ # 1 minute to launch
+ if time.time() - start_time > 60:
+ raise Exception("Timeout")
+ time.sleep(1)
+ finally:
+ result = self.conn.disassociate_address(self.data['public_ip'])
+
+ def test_005_can_revoke_security_group_ingress(self):
+ self.assertTrue(self.conn.revoke_security_group(TEST_GROUP,
+ ip_protocol='tcp',
+ from_port=80,
+ to_port=80))
+ start_time = time.time()
+ while self.__public_instance_is_accessible():
+ # 1 minute to teardown
+ if time.time() - start_time > 60:
+ raise Exception("Timeout")
+ time.sleep(1)
+
+ def test_999_tearDown(self):
+ self.conn.delete_key_pair(TEST_KEY)
+ self.conn.delete_security_group(TEST_GROUP)
+ groups = self.conn.get_all_security_groups()
+ self.assertFalse(TEST_GROUP in [group.name for group in groups])
+ self.conn.terminate_instances([self.data['instance'].id])
+ self.assertTrue(self.conn.release_address(self.data['public_ip']))
diff --git a/smoketests/test_sysadmin.py b/smoketests/test_sysadmin.py
new file mode 100644
index 000000000..4950b07e7
--- /dev/null
+++ b/smoketests/test_sysadmin.py
@@ -0,0 +1,287 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# 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 commands
+import os
+import random
+import sys
+import time
+import unittest
+
+# If ../nova/__init__.py exists, add ../ to Python search path, so that
+# it will override what happens to be installed in /usr/(local/)lib/python...
+possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
+ os.pardir,
+ os.pardir))
+if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
+ sys.path.insert(0, possible_topdir)
+
+from smoketests import flags
+from smoketests import base
+
+
+
+FLAGS = flags.FLAGS
+flags.DEFINE_string('bundle_kernel', 'openwrt-x86-vmlinuz',
+ 'Local kernel file to use for bundling tests')
+flags.DEFINE_string('bundle_image', 'openwrt-x86-ext2.image',
+ 'Local image file to use for bundling tests')
+
+TEST_PREFIX = 'test%s' % int(random.random() * 1000000)
+TEST_BUCKET = '%s_bucket' % TEST_PREFIX
+TEST_KEY = '%s_key' % TEST_PREFIX
+TEST_GROUP = '%s_group' % TEST_PREFIX
+class ImageTests(base.UserSmokeTestCase):
+ def test_001_can_bundle_image(self):
+ self.assertTrue(self.bundle_image(FLAGS.bundle_image))
+
+ def test_002_can_upload_image(self):
+ self.assertTrue(self.upload_image(TEST_BUCKET, FLAGS.bundle_image))
+
+ def test_003_can_register_image(self):
+ image_id = self.conn.register_image('%s/%s.manifest.xml' %
+ (TEST_BUCKET, FLAGS.bundle_image))
+ self.assert_(image_id is not None)
+ self.data['image_id'] = image_id
+
+ def test_004_can_bundle_kernel(self):
+ self.assertTrue(self.bundle_image(FLAGS.bundle_kernel, kernel=True))
+
+ def test_005_can_upload_kernel(self):
+ self.assertTrue(self.upload_image(TEST_BUCKET, FLAGS.bundle_kernel))
+
+ def test_006_can_register_kernel(self):
+ kernel_id = self.conn.register_image('%s/%s.manifest.xml' %
+ (TEST_BUCKET, FLAGS.bundle_kernel))
+ self.assert_(kernel_id is not None)
+ self.data['kernel_id'] = kernel_id
+
+ def test_007_images_are_available_within_10_seconds(self):
+ for i in xrange(10):
+ image = self.conn.get_image(self.data['image_id'])
+ if image and image.state == 'available':
+ break
+ time.sleep(1)
+ else:
+ self.assert_(False) # wasn't available within 10 seconds
+ self.assert_(image.type == 'machine')
+
+ for i in xrange(10):
+ kernel = self.conn.get_image(self.data['kernel_id'])
+ if kernel and kernel.state == 'available':
+ break
+ time.sleep(1)
+ else:
+ self.assert_(False) # wasn't available within 10 seconds
+ self.assert_(kernel.type == 'kernel')
+
+ def test_008_can_describe_image_attribute(self):
+ attrs = self.conn.get_image_attribute(self.data['image_id'],
+ 'launchPermission')
+ self.assert_(attrs.name, 'launch_permission')
+
+ def test_009_can_modify_image_launch_permission(self):
+ self.conn.modify_image_attribute(image_id=self.data['image_id'],
+ operation='add',
+ attribute='launchPermission',
+ groups='all')
+ image = self.conn.get_image(self.data['image_id'])
+ self.assertEqual(image.id, self.data['image_id'])
+
+ def test_010_can_see_launch_permission(self):
+ attrs = self.conn.get_image_attribute(self.data['image_id'],
+ 'launchPermission')
+ self.assert_(attrs.name, 'launch_permission')
+ self.assert_(attrs.attrs['groups'][0], 'all')
+
+ def test_011_user_can_deregister_kernel(self):
+ self.assertTrue(self.conn.deregister_image(self.data['kernel_id']))
+
+ def test_012_can_deregister_image(self):
+ self.assertTrue(self.conn.deregister_image(self.data['image_id']))
+
+ def test_013_can_delete_bundle(self):
+ self.assertTrue(self.delete_bundle_bucket(TEST_BUCKET))
+
+
+class InstanceTests(base.UserSmokeTestCase):
+ def test_001_can_create_keypair(self):
+ key = self.create_key_pair(self.conn, TEST_KEY)
+ self.assertEqual(key.name, TEST_KEY)
+
+ def test_002_can_create_instance_with_keypair(self):
+ reservation = self.conn.run_instances(FLAGS.test_image,
+ key_name=TEST_KEY,
+ instance_type='m1.tiny')
+ self.assertEqual(len(reservation.instances), 1)
+ self.data['instance'] = reservation.instances[0]
+
+ def test_003_instance_runs_within_60_seconds(self):
+ instance = self.data['instance']
+ # allow 60 seconds to exit pending with IP
+ if not self.wait_for_running(self.data['instance']):
+ self.fail('instance failed to start')
+ self.data['instance'].update()
+ ip = self.data['instance'].private_dns_name
+ self.failIf(ip == '0.0.0.0')
+ if FLAGS.use_ipv6:
+ ipv6 = self.data['instance'].dns_name_v6
+ self.failIf(ipv6 is None)
+
+ def test_004_can_ping_private_ip(self):
+ if not self.wait_for_ping(self.data['instance'].private_dns_name):
+ self.fail('could not ping instance')
+
+ if FLAGS.use_ipv6:
+ if not self.wait_for_ping(self.data['instance'].ip_v6, "ping6"):
+ self.fail('could not ping instance v6')
+
+ def test_005_can_ssh_to_private_ip(self):
+ if not self.wait_for_ssh(self.data['instance'].private_dns_name,
+ TEST_KEY):
+ self.fail('could not ssh to instance')
+
+ if FLAGS.use_ipv6:
+ if not self.wait_for_ssh(self.data['instance'].ip_v6,
+ TEST_KEY):
+ self.fail('could not ssh to instance v6')
+
+ def test_999_tearDown(self):
+ self.delete_key_pair(self.conn, TEST_KEY)
+ self.conn.terminate_instances([self.data['instance'].id])
+
+
+class VolumeTests(base.UserSmokeTestCase):
+ def setUp(self):
+ super(VolumeTests, self).setUp()
+ self.device = '/dev/vdb'
+
+ def test_000_setUp(self):
+ self.create_key_pair(self.conn, TEST_KEY)
+ reservation = self.conn.run_instances(FLAGS.test_image,
+ instance_type='m1.tiny',
+ key_name=TEST_KEY)
+ self.data['instance'] = reservation.instances[0]
+ if not self.wait_for_running(self.data['instance']):
+ self.fail('instance failed to start')
+ self.data['instance'].update()
+ if not self.wait_for_ping(self.data['instance'].private_dns_name):
+ self.fail('could not ping instance')
+ if not self.wait_for_ssh(self.data['instance'].private_dns_name,
+ TEST_KEY):
+ self.fail('could not ssh to instance')
+
+ def test_001_can_create_volume(self):
+ volume = self.conn.create_volume(1, 'nova')
+ self.assertEqual(volume.size, 1)
+ self.data['volume'] = volume
+ # Give network time to find volume.
+ time.sleep(5)
+
+ def test_002_can_attach_volume(self):
+ volume = self.data['volume']
+
+ for x in xrange(10):
+ volume.update()
+ if volume.status.startswith('available'):
+ break
+ time.sleep(1)
+ else:
+ self.fail('cannot attach volume with state %s' % volume.status)
+
+ # Give volume some time to be ready.
+ time.sleep(5)
+ volume.attach(self.data['instance'].id, self.device)
+
+ # wait
+ for x in xrange(10):
+ volume.update()
+ if volume.status.startswith('in-use'):
+ break
+ time.sleep(1)
+ else:
+ self.fail('volume never got to in use')
+
+ self.assertTrue(volume.status.startswith('in-use'))
+
+ # Give instance time to recognize volume.
+ time.sleep(5)
+
+ def test_003_can_mount_volume(self):
+ ip = self.data['instance'].private_dns_name
+ conn = self.connect_ssh(ip, TEST_KEY)
+ # NOTE(vish): this will create an dev for images that don't have
+ # udev rules
+ stdin, stdout, stderr = conn.exec_command(
+ 'grep %s /proc/partitions | '
+ '`awk \'{print "mknod /dev/"\\$4" b "\\$1" "\\$2}\'`'
+ % self.device.rpartition('/')[2])
+ exec_list = []
+ exec_list.append('mkdir -p /mnt/vol')
+ exec_list.append('/sbin/mke2fs %s' % self.device)
+ exec_list.append('mount %s /mnt/vol' % self.device)
+ exec_list.append('echo success')
+ stdin, stdout, stderr = conn.exec_command(' && '.join(exec_list))
+ out = stdout.read()
+ conn.close()
+ if not out.strip().endswith('success'):
+ self.fail('Unable to mount: %s %s' % (out, stderr.read()))
+
+ def test_004_can_write_to_volume(self):
+ ip = self.data['instance'].private_dns_name
+ conn = self.connect_ssh(ip, TEST_KEY)
+ # FIXME(devcamcar): This doesn't fail if the volume hasn't been mounted
+ stdin, stdout, stderr = conn.exec_command(
+ 'echo hello > /mnt/vol/test.txt')
+ err = stderr.read()
+ conn.close()
+ if len(err) > 0:
+ self.fail('Unable to write to mount: %s' % (err))
+
+ def test_005_volume_is_correct_size(self):
+ ip = self.data['instance'].private_dns_name
+ conn = self.connect_ssh(ip, TEST_KEY)
+ stdin, stdout, stderr = conn.exec_command(
+ "df -h | grep %s | awk {'print $2'}" % self.device)
+ out = stdout.read()
+ conn.close()
+ if not out.strip() == '1007.9M':
+ self.fail('Volume is not the right size: %s %s' %
+ (out, stderr.read()))
+
+ def test_006_me_can_umount_volume(self):
+ ip = self.data['instance'].private_dns_name
+ conn = self.connect_ssh(ip, TEST_KEY)
+ stdin, stdout, stderr = conn.exec_command('umount /mnt/vol')
+ err = stderr.read()
+ conn.close()
+ if len(err) > 0:
+ self.fail('Unable to unmount: %s' % (err))
+
+ def test_007_me_can_detach_volume(self):
+ result = self.conn.detach_volume(volume_id=self.data['volume'].id)
+ self.assertTrue(result)
+ time.sleep(5)
+
+ def test_008_me_can_delete_volume(self):
+ result = self.conn.delete_volume(self.data['volume'].id)
+ self.assertTrue(result)
+
+ def test_999_tearDown(self):
+ self.conn.terminate_instances([self.data['instance'].id])
+ self.conn.delete_key_pair(TEST_KEY)
--
cgit
From a6f607681f8eac043bfbc33c91436198f451d9e1 Mon Sep 17 00:00:00 2001
From: Vishvananda Ishaya
Date: Thu, 24 Feb 2011 21:32:27 -0800
Subject: add customizable tempdir and remove extra code
---
smoketests/base.py | 38 +++++++-------------------------------
smoketests/test_sysadmin.py | 16 ++++++++++++----
2 files changed, 19 insertions(+), 35 deletions(-)
diff --git a/smoketests/base.py b/smoketests/base.py
index 204b4a1eb..bc9aebf6b 100644
--- a/smoketests/base.py
+++ b/smoketests/base.py
@@ -22,6 +22,7 @@ import httplib
import os
import paramiko
import sys
+import tempfile
import time
import unittest
from boto.ec2.regioninfo import RegionInfo
@@ -147,19 +148,20 @@ class SmokeTestCase(unittest.TestCase):
except:
pass
- def bundle_image(self, image, kernel=False):
- cmd = 'euca-bundle-image -i %s' % image
+ def bundle_image(self, image, tempdir='/tmp', kernel=False):
+ tempdir = tempfile.mkdtemp()
+ cmd = 'euca-bundle-image -i %s -d %s' % (image, tempdir)
if kernel:
cmd += ' --kernel true'
status, output = commands.getstatusoutput(cmd)
if status != 0:
print '%s -> \n %s' % (cmd, output)
raise Exception(output)
- return True
+ return tempdir
- def upload_image(self, bucket_name, image):
+ def upload_image(self, bucket_name, image, tempdir='/tmp'):
cmd = 'euca-upload-bundle -b '
- cmd += '%s -m /tmp/%s.manifest.xml' % (bucket_name, image)
+ cmd += '%s -m %s/%s.manifest.xml' % (bucket_name, tempdir, image)
status, output = commands.getstatusoutput(cmd)
if status != 0:
print '%s -> \n %s' % (cmd, output)
@@ -183,29 +185,3 @@ class UserSmokeTestCase(SmokeTestCase):
global TEST_DATA
self.conn = self.connection_for_env()
self.data = TEST_DATA
-
-
-def run_tests(suites):
- argv = FLAGS(sys.argv)
- if FLAGS.use_ipv6:
- global boto_v6
- boto_v6 = __import__('boto_v6')
-
- if not os.getenv('EC2_ACCESS_KEY'):
- print >> sys.stderr, 'Missing EC2 environment variables. Please ' \
- 'source the appropriate novarc file before ' \
- 'running this test.'
- return 1
-
- if FLAGS.suite:
- try:
- suite = suites[FLAGS.suite]
- except KeyError:
- print >> sys.stderr, 'Available test suites:', \
- ', '.join(suites.keys())
- return 1
-
- unittest.TextTestRunner(verbosity=2).run(suite)
- else:
- for suite in suites.itervalues():
- unittest.TextTestRunner(verbosity=2).run(suite)
diff --git a/smoketests/test_sysadmin.py b/smoketests/test_sysadmin.py
index 4950b07e7..8decb56c1 100644
--- a/smoketests/test_sysadmin.py
+++ b/smoketests/test_sysadmin.py
@@ -16,12 +16,12 @@
# License for the specific language governing permissions and limitations
# under the License.
-import commands
import os
import random
import sys
import time
-import unittest
+import tempfile
+import shutil
# If ../nova/__init__.py exists, add ../ to Python search path, so that
# it will override what happens to be installed in /usr/(local/)lib/python...
@@ -48,10 +48,18 @@ TEST_KEY = '%s_key' % TEST_PREFIX
TEST_GROUP = '%s_group' % TEST_PREFIX
class ImageTests(base.UserSmokeTestCase):
def test_001_can_bundle_image(self):
- self.assertTrue(self.bundle_image(FLAGS.bundle_image))
+ self.data['tempdir'] = tempfile.mkdtemp()
+ self.assertTrue(self.bundle_image(FLAGS.bundle_image,
+ self.data['tempdir']))
def test_002_can_upload_image(self):
- self.assertTrue(self.upload_image(TEST_BUCKET, FLAGS.bundle_image))
+ try:
+ self.assertTrue(self.upload_image(TEST_BUCKET,
+ FLAGS.bundle_image,
+ self.data['tempdir']))
+ finally:
+ if os.path.exists(self.data['tempdir']):
+ shutil.rmtree(self.data['tempdir'])
def test_003_can_register_image(self):
image_id = self.conn.register_image('%s/%s.manifest.xml' %
--
cgit
From 24eb5c0b787d2031999aff21c471b0d9220083e3 Mon Sep 17 00:00:00 2001
From: Vishvananda Ishaya
Date: Thu, 24 Feb 2011 21:33:26 -0800
Subject: removed unused references to unittest
---
smoketests/public_network_smoketests.py | 1 -
smoketests/test_netadmin.py | 1 -
2 files changed, 2 deletions(-)
diff --git a/smoketests/public_network_smoketests.py b/smoketests/public_network_smoketests.py
index aa1fc548f..0ba477b7c 100644
--- a/smoketests/public_network_smoketests.py
+++ b/smoketests/public_network_smoketests.py
@@ -21,7 +21,6 @@ import os
import random
import sys
import time
-import unittest
# If ../nova/__init__.py exists, add ../ to Python search path, so that
# it will override what happens to be installed in /usr/(local/)lib/python...
diff --git a/smoketests/test_netadmin.py b/smoketests/test_netadmin.py
index 4f033e4bc..60086f065 100644
--- a/smoketests/test_netadmin.py
+++ b/smoketests/test_netadmin.py
@@ -21,7 +21,6 @@ import os
import random
import sys
import time
-import unittest
# If ../nova/__init__.py exists, add ../ to Python search path, so that
# it will override what happens to be installed in /usr/(local/)lib/python...
--
cgit
From bc7b96f11ee2ee949182f7128db6b9ff1866a247 Mon Sep 17 00:00:00 2001
From: Vishvananda Ishaya
Date: Thu, 24 Feb 2011 22:02:50 -0800
Subject: revert a few unnecessary changes to base.py
---
smoketests/base.py | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/smoketests/base.py b/smoketests/base.py
index bc9aebf6b..e9924f0ef 100644
--- a/smoketests/base.py
+++ b/smoketests/base.py
@@ -22,7 +22,6 @@ import httplib
import os
import paramiko
import sys
-import tempfile
import time
import unittest
from boto.ec2.regioninfo import RegionInfo
@@ -149,7 +148,6 @@ class SmokeTestCase(unittest.TestCase):
pass
def bundle_image(self, image, tempdir='/tmp', kernel=False):
- tempdir = tempfile.mkdtemp()
cmd = 'euca-bundle-image -i %s -d %s' % (image, tempdir)
if kernel:
cmd += ' --kernel true'
@@ -157,7 +155,7 @@ class SmokeTestCase(unittest.TestCase):
if status != 0:
print '%s -> \n %s' % (cmd, output)
raise Exception(output)
- return tempdir
+ return True
def upload_image(self, bucket_name, image, tempdir='/tmp'):
cmd = 'euca-upload-bundle -b '
--
cgit
From 20e9df05acdb89382023af1ac98cf040c827e18d Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Fri, 25 Feb 2011 14:49:33 -0800
Subject: DescribeInstances modified to return ipv6 fixed ip address in case of
flatmanager
---
nova/api/ec2/cloud.py | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 7458d307a..15799670c 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -701,9 +701,13 @@ class CloudController(object):
fixed = instance['fixed_ip']
floating_addr = fixed['floating_ips'][0]['address']
if instance['fixed_ip']['network'] and 'use_v6' in kwargs:
- i['dnsNameV6'] = utils.to_global_ipv6(
- instance['fixed_ip']['network']['cidr_v6'],
- instance['mac_address'])
+ if FLAGS.network_manager == \
+ 'nova.network.manager.FlatManager':
+ i['dnsNameV6'] = instance['fixed_ip']['addressv6']
+ else:
+ i['dnsNameV6'] = utils.to_global_ipv6(
+ instance['fixed_ip']['network']['cidr_v6'],
+ instance['mac_address'])
i['privateDnsName'] = fixed_addr
i['publicDnsName'] = floating_addr
--
cgit
From 5bb77cb83ea443e5e3ae4b4000763e4289f8e87a Mon Sep 17 00:00:00 2001
From: Vishvananda Ishaya
Date: Fri, 25 Feb 2011 23:58:36 -0800
Subject: add timeout and retry for ssh
---
smoketests/base.py | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/smoketests/base.py b/smoketests/base.py
index e9924f0ef..3e2446c9a 100644
--- a/smoketests/base.py
+++ b/smoketests/base.py
@@ -31,17 +31,24 @@ from smoketests import flags
SUITE_NAMES = '[image, instance, volume]'
FLAGS = flags.FLAGS
flags.DEFINE_string('suite', None, 'Specific test suite to run ' + SUITE_NAMES)
+flags.DEFINE_integer('ssh_tries', 3, 'Numer of times to try ssh')
boto_v6 = None
class SmokeTestCase(unittest.TestCase):
def connect_ssh(self, ip, key_name):
- # TODO(devcamcar): set a more reasonable connection timeout time
key = paramiko.RSAKey.from_private_key_file('/tmp/%s.pem' % key_name)
- client = paramiko.SSHClient()
- client.set_missing_host_key_policy(paramiko.WarningPolicy())
- client.connect(ip, username='root', pkey=key)
- return client
+ tries = 0
+ while(True):
+ try:
+ client = paramiko.SSHClient()
+ client.set_missing_host_key_policy(paramiko.WarningPolicy())
+ client.connect(ip, username='root', pkey=key, timeout=5)
+ return client
+ except (paramiko.AuthenticationException, paramiko.SSHException):
+ tries += 1
+ if tries == FLAGS.ssh_tries:
+ raise
def can_ping(self, ip, command="ping"):
"""Attempt to ping the specified IP, and give up after 1 second."""
--
cgit
From df0a4d66f7059db94e1de365fed8b8d244e16534 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Tue, 1 Mar 2011 17:12:47 -0800
Subject: Changed ra_server to gateway_v6 and removed addressv6 column from
fixed_ips db table
---
nova/api/ec2/cloud.py | 4 ---
nova/db/sqlalchemy/api.py | 11 +++---
.../versions/007_add_ipv6_flatmanager.py | 24 ++++---------
nova/db/sqlalchemy/models.py | 5 ++-
nova/network/linux_net.py | 2 +-
nova/network/manager.py | 37 +++++---------------
nova/virt/interfaces.template | 6 ++--
nova/virt/libvirt.xml.template | 4 +--
nova/virt/libvirt_conn.py | 40 +++++++++++-----------
9 files changed, 47 insertions(+), 86 deletions(-)
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 15799670c..b3779a4da 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -701,10 +701,6 @@ class CloudController(object):
fixed = instance['fixed_ip']
floating_addr = fixed['floating_ips'][0]['address']
if instance['fixed_ip']['network'] and 'use_v6' in kwargs:
- if FLAGS.network_manager == \
- 'nova.network.manager.FlatManager':
- i['dnsNameV6'] = instance['fixed_ip']['addressv6']
- else:
i['dnsNameV6'] = utils.to_global_ipv6(
instance['fixed_ip']['network']['cidr_v6'],
instance['mac_address'])
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 9bc59de60..d8751bef4 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -833,13 +833,10 @@ def instance_get_fixed_address_v6(context, instance_id):
session = get_session()
with session.begin():
instance_ref = instance_get(context, instance_id, session=session)
- if 'nova.network.manager.FlatManager' == FLAGS.network_manager:
- return instance_ref.fixed_ip['addressv6']
- else:
- network_ref = network_get_by_instance(context, instance_id)
- prefix = network_ref.cidr_v6
- mac = instance_ref.mac_address
- return utils.to_global_ipv6(prefix, mac)
+ network_ref = network_get_by_instance(context, instance_id)
+ prefix = network_ref.cidr_v6
+ mac = instance_ref.mac_address
+ return utils.to_global_ipv6(prefix, mac)
@require_context
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
index 2951cbc0a..e09f46652 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
@@ -30,10 +30,6 @@ networks = Table('networks', meta,
Column('id', Integer(), primary_key=True, nullable=False),
)
-fixed_ips = Table('fixed_ips', meta,
- Column('id', Integer(), primary_key=True, nullable=False),
- )
-
#
# New Tables
#
@@ -42,24 +38,19 @@ fixed_ips = Table('fixed_ips', meta,
#
# Tables to alter
#
-# None
+
#
# Columns to add to existing tables
#
-networks_gatewayv6 = Column(
- 'gatewayv6',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False))
-
-networks_netmaskv6 = Column(
- 'netmaskv6',
+networks_gateway_v6 = Column(
+ 'gateway_v6',
String(length=255, convert_unicode=False, assert_unicode=None,
unicode_error=None, _warn_on_bytestring=False))
-fixed_ips_addressv6 = Column(
- 'addressv6',
+networks_netmask_v6 = Column(
+ 'netmask_v6',
String(length=255, convert_unicode=False, assert_unicode=None,
unicode_error=None, _warn_on_bytestring=False))
@@ -70,6 +61,5 @@ def upgrade(migrate_engine):
meta.bind = migrate_engine
# Add columns to existing tables
- networks.create_column(networks_gatewayv6)
- networks.create_column(networks_netmaskv6)
- fixed_ips.create_column(fixed_ips_addressv6)
+ networks.create_column(networks_gateway_v6)
+ networks.create_column(networks_netmask_v6)
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 4fa4d443c..f235054d2 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -385,8 +385,8 @@ class Network(BASE, NovaBase):
ra_server = Column(String(255))
- gatewayv6 = Column(String(255))
- netmaskv6 = Column(String(255))
+ gateway_v6 = Column(String(255))
+ netmask_v6 = Column(String(255))
netmask = Column(String(255))
bridge = Column(String(255))
gateway = Column(String(255))
@@ -427,7 +427,6 @@ class FixedIp(BASE, NovaBase):
__tablename__ = 'fixed_ips'
id = Column(Integer, primary_key=True)
address = Column(String(255))
- addressv6 = Column(String(255))
network_id = Column(Integer, ForeignKey('networks.id'), nullable=True)
network = relationship(Network, backref=backref('fixed_ips'))
instance_id = Column(Integer, ForeignKey('instances.id'), nullable=True)
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index 535ce87bc..e375568f1 100644
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -361,7 +361,7 @@ interface %s
command = _ra_cmd(network_ref)
_execute(command)
db.network_update(context, network_id,
- {"ra_server":
+ {"gateway_v6":
utils.get_my_linklocal(network_ref['bridge'])})
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 61b5dc07f..bdeeae293 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -388,41 +388,14 @@ class FlatManager(NetworkManager):
significant_bits_v6)
net['cidr_v6'] = cidr_v6
project_net_v6 = IPy.IP(cidr_v6)
- net['gatewayv6'] = str(project_net_v6[1])
- net['netmaskv6'] = str(project_net_v6.prefixlen())
+ net['gateway_v6'] = str(project_net_v6[1])
+ net['netmask_v6'] = str(project_net_v6.prefixlen())
network_ref = self.db.network_create_safe(context, net)
if network_ref:
self._create_fixed_ips(context, network_ref['id'])
- def _create_fixed_ips(self, context, network_id):
- """Create all fixed ips for network."""
- network_ref = self.db.network_get(context, network_id)
- # NOTE(vish): Should these be properties of the network as opposed
- # to properties of the manager class?
- bottom_reserved = self._bottom_reserved_ips
- top_reserved = self._top_reserved_ips
- project_net = IPy.IP(network_ref['cidr'])
-
- if(FLAGS.use_ipv6):
- project_net_v6 = IPy.IP(network_ref['cidr_v6'])
-
- num_ips = len(project_net)
- addressv6 = None
- for index in range(num_ips):
- address = str(project_net[index])
- if(FLAGS.use_ipv6):
- addressv6 = str(project_net_v6[index])
- if index < bottom_reserved or num_ips - index < top_reserved:
- reserved = True
- else:
- reserved = False
- self.db.fixed_ip_create(context, {'network_id': network_id,
- 'address': address,
- 'addressv6': addressv6,
- 'reserved': reserved})
-
def get_network_host(self, context):
"""Get the network host for the current context."""
network_ref = self.db.network_get_by_bridge(context,
@@ -448,6 +421,12 @@ class FlatManager(NetworkManager):
net = {}
net['injected'] = FLAGS.flat_injected
net['dns'] = FLAGS.flat_network_dns
+
+ if not FLAGS.fake_network:
+ if(FLAGS.use_ipv6):
+ net['gateway_v6'] = \
+ utils.get_my_linklocal(FLAGS.flat_network_bridge)
+
self.db.network_update(context, network_id, net)
def allocate_floating_ip(self, context, project_id):
diff --git a/nova/virt/interfaces.template b/nova/virt/interfaces.template
index 1db745f9f..3b34e54f4 100644
--- a/nova/virt/interfaces.template
+++ b/nova/virt/interfaces.template
@@ -16,8 +16,8 @@ iface eth0 inet static
#if $use_ipv6
iface eth0 inet6 static
- address ${addressv6}
- netmask ${netmaskv6}
- gateway ${gatewayv6}
+ address ${address_v6}
+ netmask ${netmask_v6}
+ gateway ${gateway_v6}
#end if
diff --git a/nova/virt/libvirt.xml.template b/nova/virt/libvirt.xml.template
index 88bfbc668..ef2d2cd6b 100644
--- a/nova/virt/libvirt.xml.template
+++ b/nova/virt/libvirt.xml.template
@@ -79,8 +79,8 @@
#if $getVar('extra_params', False)
${extra_params}
#end if
-#if $getVar('ra_server', False)
-
+#if $getVar('gateway_v6', False)
+
#end if
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index b7712f76e..38fa2338e 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -631,21 +631,21 @@ class LibvirtConnection(object):
admin_context = context.get_admin_context()
address = db.instance_get_fixed_address(admin_context,
inst['id'])
- addressv6 = db.instance_get_fixed_address_v6(admin_context,
+ address_v6 = db.instance_get_fixed_address_v6(admin_context,
inst['id'])
- ra_server = network_ref['ra_server']
- if not ra_server:
- ra_server = "fd00::"
+ gateway_v6 = network_ref['gateway_v6']
+ if not gateway_v6:
+ gateway_v6 = "fd00::"
interfaces_info = {'address': address,
'netmask': network_ref['netmask'],
'gateway': network_ref['gateway'],
'broadcast': network_ref['broadcast'],
'dns': network_ref['dns'],
- 'ra_server': ra_server,
- 'addressv6': addressv6,
- 'gatewayv6': network_ref['gatewayv6'],
- 'netmaskv6': network_ref['netmaskv6'],
+ 'gateway_v6': gateway_v6,
+ 'address_v6': address_v6,
+ 'gateway_v6': network_ref['gateway_v6'],
+ 'netmask_v6': network_ref['netmask_v6'],
'use_ipv6': FLAGS.use_ipv6}
net = str(Template(self.interfaces_xml,
@@ -683,7 +683,7 @@ class LibvirtConnection(object):
instance['id'])
# Assume that the gateway also acts as the dhcp server.
dhcp_server = network['gateway']
- ra_server = network['ra_server']
+ gateway_v6 = network['gateway_v6']
if FLAGS.allow_project_net_traffic:
if FLAGS.use_ipv6:
@@ -728,8 +728,8 @@ class LibvirtConnection(object):
'local': instance_type['local_gb'],
'driver_type': driver_type}
- if ra_server:
- xml_info['ra_server'] = ra_server + "/128"
+ if gateway_v6:
+ xml_info['gateway_v6'] = gateway_v6 + "/128"
if not rescue:
if instance['kernel_id']:
xml_info['kernel'] = xml_info['basepath'] + "/kernel"
@@ -921,10 +921,10 @@ class FirewallDriver(object):
"""
raise NotImplementedError()
- def _ra_server_for_instance(self, instance):
+ def _gateway_v6_for_instance(self, instance):
network = db.network_get_by_instance(context.get_admin_context(),
instance['id'])
- return network['ra_server']
+ return network['gateway_v6']
class NWFilterFirewall(FirewallDriver):
@@ -1140,8 +1140,8 @@ class NWFilterFirewall(FirewallDriver):
'nova-base-ipv6',
'nova-allow-dhcp-server']
if FLAGS.use_ipv6:
- ra_server = self._ra_server_for_instance(instance)
- if ra_server:
+ gateway_v6 = self._gateway_v6_for_instance(instance)
+ if gateway_v6:
instance_secgroup_filter_children += ['nova-allow-ra-server']
ctxt = context.get_admin_context()
@@ -1328,10 +1328,10 @@ class IptablesFirewallDriver(FirewallDriver):
our_rules += ['-A %s -s %s -j ACCEPT' % (chain_name, cidr)]
elif(ip_version == 6):
# Allow RA responses
- ra_server = self._ra_server_for_instance(instance)
- if ra_server:
+ gateway_v6 = self._gateway_v6_for_instance(instance)
+ if gateway_v6:
our_rules += ['-A %s -s %s -p icmpv6 -j ACCEPT' %
- (chain_name, ra_server + "/128")]
+ (chain_name, gateway_v6 + "/128")]
#Allow project network traffic
if (FLAGS.allow_project_net_traffic):
cidrv6 = self._project_cidrv6_for_instance(instance)
@@ -1427,10 +1427,10 @@ class IptablesFirewallDriver(FirewallDriver):
instance['id'])
return network['gateway']
- def _ra_server_for_instance(self, instance):
+ def _gateway_v6_for_instance(self, instance):
network = db.network_get_by_instance(context.get_admin_context(),
instance['id'])
- return network['ra_server']
+ return network['gateway_v6']
def _project_cidr_for_instance(self, instance):
network = db.network_get_by_instance(context.get_admin_context(),
--
cgit
From 0a9ba675c88ae0b2a18f47524d24075409261658 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Thu, 3 Mar 2011 15:39:23 -0800
Subject: altered ra_server name to gateway_v6
---
.../versions/007_add_ipv6_flatmanager.py | 14 ++--
.../versions/007_add_ipv6_to_fixed_ips.py | 90 ----------------------
2 files changed, 6 insertions(+), 98 deletions(-)
delete mode 100644 nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_to_fixed_ips.py
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
index e09f46652..937712970 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
@@ -28,7 +28,10 @@ meta = MetaData()
#
networks = Table('networks', meta,
Column('id', Integer(), primary_key=True, nullable=False),
- )
+ Column('ra_server', String(length=255, convert_unicode=False,
+ assert_unicode=None, unicode_error=None,
+ _warn_on_bytestring=False))
+ )
#
# New Tables
@@ -43,12 +46,6 @@ networks = Table('networks', meta,
#
# Columns to add to existing tables
#
-
-networks_gateway_v6 = Column(
- 'gateway_v6',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False))
-
networks_netmask_v6 = Column(
'netmask_v6',
String(length=255, convert_unicode=False, assert_unicode=None,
@@ -60,6 +57,7 @@ def upgrade(migrate_engine):
# bind migrate_engine to your metadata
meta.bind = migrate_engine
+ # Alter column name
+ networks.c.ra_server.alter(name='gateway_v6')
# Add columns to existing tables
- networks.create_column(networks_gateway_v6)
networks.create_column(networks_netmask_v6)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_to_fixed_ips.py b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_to_fixed_ips.py
deleted file mode 100644
index 427934d53..000000000
--- a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_to_fixed_ips.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# Copyright 2011 OpenStack LLC
-# All Rights Reserved.
-#
-# 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.
-
-from sqlalchemy import *
-from migrate import *
-
-from nova import log as logging
-
-
-meta = MetaData()
-
-
-# Table stub-definitions
-# Just for the ForeignKey and column creation to succeed, these are not the
-# actual definitions of instances or services.
-#
-fixed_ips = Table(
- "fixed_ips",
- meta,
- Column(
- "id",
- Integer(),
- primary_key=True,
- nullable=False))
-
-#
-# New Tables
-#
-# None
-
-#
-# Tables to alter
-#
-# None
-
-#
-# Columns to add to existing tables
-#
-
-fixed_ips_addressV6 = Column(
- "addressV6",
- String(
- length=255,
- convert_unicode=False,
- assert_unicode=None,
- unicode_error=None,
- _warn_on_bytestring=False))
-
-
-fixed_ips_netmaskV6 = Column(
- "netmaskV6",
- String(
- length=3,
- convert_unicode=False,
- assert_unicode=None,
- unicode_error=None,
- _warn_on_bytestring=False))
-
-
-fixed_ips_gatewayV6 = Column(
- "gatewayV6",
- String(
- length=255,
- convert_unicode=False,
- assert_unicode=None,
- unicode_error=None,
- _warn_on_bytestring=False))
-
-
-def upgrade(migrate_engine):
- # Upgrade operations go here. Don't create your own engine;
- # bind migrate_engine to your metadata
- meta.bind = migrate_engine
-
- # Add columns to existing tables
- fixed_ips.create_column(fixed_ips_addressV6)
- fixed_ips.create_column(fixed_ips_netmaskV6)
- fixed_ips.create_column(fixed_ips_gatewayV6)
--
cgit
From 35be7d39866f6ac1017dd94d33d9c01f47a6bc74 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Thu, 3 Mar 2011 15:44:01 -0800
Subject: Removed properties added to fixed_ips by xs-ipv6 BP
---
nova/db/sqlalchemy/models.py | 3 ---
nova/network/manager.py | 2 +-
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 4c94cd3db..7b4683427 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -458,9 +458,6 @@ class FixedIp(BASE, NovaBase):
allocated = Column(Boolean, default=False)
leased = Column(Boolean, default=False)
reserved = Column(Boolean, default=False)
- addressV6 = Column(String(255))
- netmaskV6 = Column(String(3))
- gatewayV6 = Column(String(255))
class User(BASE, NovaBase):
diff --git a/nova/network/manager.py b/nova/network/manager.py
index fb6e16772..686ab9732 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -167,7 +167,7 @@ class NetworkManager(manager.Manager):
# with a network, or a cluster of computes with a network
# and use that network here with a method like
# network_get_by_compute_host
- network_ref = self.db.network_get_by_bridge(context,
+ network_ref = self.db.network_get_by_bridge(context.elevated(),
FLAGS.flat_network_bridge)
address = self.db.fixed_ip_associate_pool(context.elevated(),
network_ref['id'],
--
cgit
From aa09f87060c1d1885b7a557ff26a3c421ad42df8 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Thu, 3 Mar 2011 17:31:37 -0800
Subject: remove ra_server from model and fix migration issue while running
unit tests
---
.../versions/007_add_ipv6_flatmanager.py | 60 +++++++++++++++++++---
nova/db/sqlalchemy/models.py | 2 -
2 files changed, 54 insertions(+), 8 deletions(-)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
index 937712970..d14f52af1 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
@@ -12,6 +12,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
+from lib2to3.fixer_util import String
from sqlalchemy import *
from migrate import *
@@ -27,12 +28,59 @@ meta = MetaData()
# actual definitions of instances or services.
#
networks = Table('networks', meta,
+ Column('created_at', DateTime(timezone=False)),
+ Column('updated_at', DateTime(timezone=False)),
+ Column('deleted_at', DateTime(timezone=False)),
+ Column('deleted', Boolean(create_constraint=True, name=None)),
Column('id', Integer(), primary_key=True, nullable=False),
- Column('ra_server', String(length=255, convert_unicode=False,
- assert_unicode=None, unicode_error=None,
- _warn_on_bytestring=False))
- )
-
+ Column('injected', Boolean(create_constraint=True, name=None)),
+ Column('cidr',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('netmask',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('bridge',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('gateway',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('broadcast',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('dns',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('vlan', Integer()),
+ Column('vpn_public_address',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('vpn_public_port', Integer()),
+ Column('vpn_private_address',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('dhcp_start',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('project_id',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('host',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('cidr_v6',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column(
+ 'ra_server',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column(
+ 'label',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False))
+ )
#
# New Tables
#
@@ -59,5 +107,5 @@ def upgrade(migrate_engine):
# Alter column name
networks.c.ra_server.alter(name='gateway_v6')
- # Add columns to existing tables
+ # Add new column to existing table
networks.create_column(networks_netmask_v6)
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 7b4683427..14ff46647 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -402,8 +402,6 @@ class Network(BASE, NovaBase):
cidr = Column(String(255), unique=True)
cidr_v6 = Column(String(255), unique=True)
- ra_server = Column(String(255))
-
gateway_v6 = Column(String(255))
netmask_v6 = Column(String(255))
netmask = Column(String(255))
--
cgit
From 1831f31af0ac21ded3535f15777bd5147c615c34 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Fri, 4 Mar 2011 11:52:18 -0800
Subject: added flatmanager unit testcases and renamed test_network.py to
test_vlan_network.py
---
nova/tests/test_flat_network.py | 276 +++++++++++++++++++++++++++++
nova/tests/test_network.py | 369 ---------------------------------------
nova/tests/test_vlan_network.py | 373 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 649 insertions(+), 369 deletions(-)
create mode 100644 nova/tests/test_flat_network.py
delete mode 100644 nova/tests/test_network.py
create mode 100644 nova/tests/test_vlan_network.py
diff --git a/nova/tests/test_flat_network.py b/nova/tests/test_flat_network.py
new file mode 100644
index 000000000..91a49920d
--- /dev/null
+++ b/nova/tests/test_flat_network.py
@@ -0,0 +1,276 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# 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.
+"""
+Unit Tests for network code
+"""
+import IPy
+import os
+import unittest
+
+from nova import context
+from nova import db
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import test
+from nova import utils
+from nova.auth import manager
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.network')
+
+
+class FlatNetworkTestCase(test.TestCase):
+ """Test cases for network code"""
+ def setUp(self):
+ super(FlatNetworkTestCase, self).setUp()
+ # NOTE(vish): if you change these flags, make sure to change the
+ # flags in the corresponding section in nova-dhcpbridge
+ self.flags(connection_type='fake',
+ fake_call=True,
+ fake_network=True)
+ self.manager = manager.AuthManager()
+ self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
+ self.projects = []
+ self.network = utils.import_object(FLAGS.network_manager)
+ self.context = context.RequestContext(project=None, user=self.user)
+ for i in range(5):
+ name = 'project%s' % i
+ project = self.manager.create_project(name, 'netuser', name)
+ self.projects.append(project)
+ # create the necessary network data for the project
+ user_context = context.RequestContext(project=self.projects[i],
+ user=self.user)
+ host = self.network.get_network_host(user_context.elevated())
+ instance_ref = self._create_instance(0)
+ self.instance_id = instance_ref['id']
+ instance_ref = self._create_instance(1)
+ self.instance2_id = instance_ref['id']
+
+ def tearDown(self):
+ # TODO(termie): this should really be instantiating clean datastores
+ # in between runs, one failure kills all the tests
+ db.instance_destroy(context.get_admin_context(), self.instance_id)
+ db.instance_destroy(context.get_admin_context(), self.instance2_id)
+ for project in self.projects:
+ self.manager.delete_project(project)
+ self.manager.delete_user(self.user)
+ super(FlatNetworkTestCase, self).tearDown()
+
+ def _create_instance(self, project_num, mac=None):
+ if not mac:
+ mac = utils.generate_mac()
+ project = self.projects[project_num]
+ self.context._project = project
+ self.context.project_id = project.id
+ return db.instance_create(self.context,
+ {'project_id': project.id,
+ 'mac_address': mac})
+
+ def _create_address(self, project_num, instance_id=None):
+ """Create an address in given project num"""
+ if instance_id is None:
+ instance_id = self.instance_id
+ self.context._project = self.projects[project_num]
+ self.context.project_id = self.projects[project_num].id
+ return self.network.allocate_fixed_ip(self.context, instance_id)
+
+ def _deallocate_address(self, project_num, address):
+ self.context._project = self.projects[project_num]
+ self.context.project_id = self.projects[project_num].id
+ self.network.deallocate_fixed_ip(self.context, address)
+
+ def test_private_ipv6(self):
+ """Make sure ipv6 is OK"""
+ if FLAGS.use_ipv6:
+ instance_ref = self._create_instance(0)
+ address = self._create_address(0, instance_ref['id'])
+ network_ref = db.project_get_network(
+ context.get_admin_context(),
+ self.context.project_id)
+ address_v6 = db.instance_get_fixed_address_v6(
+ context.get_admin_context(),
+ instance_ref['id'])
+ self.assertEqual(instance_ref['mac_address'],
+ utils.to_mac(address_v6))
+ instance_ref2 = db.fixed_ip_get_instance_v6(
+ context.get_admin_context(),
+ address_v6)
+ self.assertEqual(instance_ref['id'], instance_ref2['id'])
+ self.assertEqual(address_v6,
+ utils.to_global_ipv6(
+ network_ref['cidr_v6'],
+ instance_ref['mac_address']))
+ self._deallocate_address(0, address)
+ db.instance_destroy(context.get_admin_context(),
+ instance_ref['id'])
+
+ def test_public_network_association(self):
+ """Makes sure that we can allocate a public ip"""
+ # TODO(vish): better way of adding floating ips
+
+ self.context._project = self.projects[0]
+ self.context.project_id = self.projects[0].id
+ pubnet = IPy.IP(flags.FLAGS.floating_range)
+ address = str(pubnet[0])
+ try:
+ db.floating_ip_get_by_address(context.get_admin_context(), address)
+ except exception.NotFound:
+ db.floating_ip_create(context.get_admin_context(),
+ {'address': address,
+ 'host': FLAGS.host})
+
+ self.assertRaises(NotImplementedError,
+ self.network.allocate_floating_ip,
+ self.context, self.projects[0].id)
+
+ fix_addr = self._create_address(0)
+ float_addr = address
+ self.assertRaises(NotImplementedError,
+ self.network.associate_floating_ip,
+ self.context, float_addr, fix_addr)
+
+ address = db.instance_get_floating_address(context.get_admin_context(),
+ self.instance_id)
+ self.assertEqual(address, None)
+
+ self.assertRaises(NotImplementedError,
+ self.network.disassociate_floating_ip,
+ self.context, float_addr)
+
+ address = db.instance_get_floating_address(context.get_admin_context(),
+ self.instance_id)
+ self.assertEqual(address, None)
+
+ self.assertRaises(NotImplementedError,
+ self.network.deallocate_floating_ip,
+ self.context, float_addr)
+
+ self.network.deallocate_fixed_ip(self.context, fix_addr)
+ db.floating_ip_destroy(context.get_admin_context(), float_addr)
+
+ def test_allocate_deallocate_fixed_ip(self):
+ """Makes sure that we can allocate and deallocate a fixed ip"""
+ address = self._create_address(0)
+ self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+ self._deallocate_address(0, address)
+
+ # check if the fixed ip address is really deallocated
+ self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+
+ def test_side_effects(self):
+ """Ensures allocating and releasing has no side effects"""
+ address = self._create_address(0)
+ address2 = self._create_address(1, self.instance2_id)
+
+ self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+ self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
+
+ self._deallocate_address(0, address)
+ self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+
+ # First address release shouldn't affect the second
+ self.assertTrue(is_allocated_in_project(address2, self.projects[0].id))
+
+ self._deallocate_address(1, address2)
+ self.assertFalse(is_allocated_in_project(address2,
+ self.projects[1].id))
+
+ def test_ips_are_reused(self):
+ """Makes sure that ip addresses that are deallocated get reused"""
+ address = self._create_address(0)
+ self.network.deallocate_fixed_ip(self.context, address)
+
+ address2 = self._create_address(0)
+ self.assertEqual(address, address2)
+
+ self.network.deallocate_fixed_ip(self.context, address2)
+
+ def test_available_ips(self):
+ """Make sure the number of available ips for the network is correct
+
+ The number of available IP addresses depends on the test
+ environment's setup.
+
+ Network size is set in test fixture's setUp method.
+
+ There are ips reserved at the bottom and top of the range.
+ services (network, gateway, CloudPipe, broadcast)
+ """
+ network = db.project_get_network(context.get_admin_context(),
+ self.projects[0].id)
+ net_size = flags.FLAGS.network_size
+ admin_context = context.get_admin_context()
+ total_ips = (db.network_count_available_ips(admin_context,
+ network['id']) +
+ db.network_count_reserved_ips(admin_context,
+ network['id']) +
+ db.network_count_allocated_ips(admin_context,
+ network['id']))
+ self.assertEqual(total_ips, net_size)
+
+ def test_too_many_addresses(self):
+ """Test for a NoMoreAddresses exception when all fixed ips are used.
+ """
+ admin_context = context.get_admin_context()
+ network = db.project_get_network(admin_context, self.projects[0].id)
+ num_available_ips = db.network_count_available_ips(admin_context,
+ network['id'])
+ addresses = []
+ instance_ids = []
+ for i in range(num_available_ips):
+ instance_ref = self._create_instance(0)
+ instance_ids.append(instance_ref['id'])
+ address = self._create_address(0, instance_ref['id'])
+ addresses.append(address)
+
+ ip_count = db.network_count_available_ips(context.get_admin_context(),
+ network['id'])
+ self.assertEqual(ip_count, 0)
+ self.assertRaises(db.NoMoreAddresses,
+ self.network.allocate_fixed_ip,
+ self.context,
+ 'foo')
+
+ for i in range(num_available_ips):
+ self.network.deallocate_fixed_ip(self.context, addresses[i])
+ db.instance_destroy(context.get_admin_context(), instance_ids[i])
+ ip_count = db.network_count_available_ips(context.get_admin_context(),
+ network['id'])
+ self.assertEqual(ip_count, num_available_ips)
+
+ def run(self, result=None):
+ if(FLAGS.network_manager == 'nova.network.manager.FlatManager'):
+ super(FlatNetworkTestCase, self).run(result)
+
+
+def is_allocated_in_project(address, project_id):
+ """Returns true if address is in specified project"""
+ #project_net = db.project_get_network(context.get_admin_context(),
+ # project_id)
+ project_net = db.network_get_by_bridge(context.get_admin_context(),
+ FLAGS.flat_network_bridge)
+ network = db.fixed_ip_get_network(context.get_admin_context(), address)
+ instance = db.fixed_ip_get_instance(context.get_admin_context(), address)
+ # instance exists until release
+ return instance is not None and network['id'] == project_net['id']
+
+
+def binpath(script):
+ """Returns the absolute path to a script in bin"""
+ return os.path.abspath(os.path.join(__file__, "../../../bin", script))
diff --git a/nova/tests/test_network.py b/nova/tests/test_network.py
deleted file mode 100644
index ce1c77210..000000000
--- a/nova/tests/test_network.py
+++ /dev/null
@@ -1,369 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# 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.
-"""
-Unit Tests for network code
-"""
-import IPy
-import os
-
-from nova import context
-from nova import db
-from nova import exception
-from nova import flags
-from nova import log as logging
-from nova import test
-from nova import utils
-from nova.auth import manager
-
-FLAGS = flags.FLAGS
-LOG = logging.getLogger('nova.tests.network')
-
-
-class NetworkTestCase(test.TestCase):
- """Test cases for network code"""
- def setUp(self):
- super(NetworkTestCase, self).setUp()
- # NOTE(vish): if you change these flags, make sure to change the
- # flags in the corresponding section in nova-dhcpbridge
- self.flags(connection_type='fake',
- fake_call=True,
- fake_network=True)
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
- self.projects = []
- self.network = utils.import_object(FLAGS.network_manager)
- self.context = context.RequestContext(project=None, user=self.user)
- for i in range(FLAGS.num_networks):
- name = 'project%s' % i
- project = self.manager.create_project(name, 'netuser', name)
- self.projects.append(project)
- # create the necessary network data for the project
- user_context = context.RequestContext(project=self.projects[i],
- user=self.user)
- host = self.network.get_network_host(user_context.elevated())
- instance_ref = self._create_instance(0)
- self.instance_id = instance_ref['id']
- instance_ref = self._create_instance(1)
- self.instance2_id = instance_ref['id']
-
- def tearDown(self):
- # TODO(termie): this should really be instantiating clean datastores
- # in between runs, one failure kills all the tests
- db.instance_destroy(context.get_admin_context(), self.instance_id)
- db.instance_destroy(context.get_admin_context(), self.instance2_id)
- for project in self.projects:
- self.manager.delete_project(project)
- self.manager.delete_user(self.user)
- super(NetworkTestCase, self).tearDown()
-
- def _create_instance(self, project_num, mac=None):
- if not mac:
- mac = utils.generate_mac()
- project = self.projects[project_num]
- self.context._project = project
- self.context.project_id = project.id
- return db.instance_create(self.context,
- {'project_id': project.id,
- 'mac_address': mac})
-
- def _create_address(self, project_num, instance_id=None):
- """Create an address in given project num"""
- if instance_id is None:
- instance_id = self.instance_id
- self.context._project = self.projects[project_num]
- self.context.project_id = self.projects[project_num].id
- return self.network.allocate_fixed_ip(self.context, instance_id)
-
- def _deallocate_address(self, project_num, address):
- self.context._project = self.projects[project_num]
- self.context.project_id = self.projects[project_num].id
- self.network.deallocate_fixed_ip(self.context, address)
-
- def test_private_ipv6(self):
- """Make sure ipv6 is OK"""
- if FLAGS.use_ipv6:
- instance_ref = self._create_instance(0)
- address = self._create_address(0, instance_ref['id'])
- network_ref = db.project_get_network(
- context.get_admin_context(),
- self.context.project_id)
- address_v6 = db.instance_get_fixed_address_v6(
- context.get_admin_context(),
- instance_ref['id'])
- self.assertEqual(instance_ref['mac_address'],
- utils.to_mac(address_v6))
- instance_ref2 = db.fixed_ip_get_instance_v6(
- context.get_admin_context(),
- address_v6)
- self.assertEqual(instance_ref['id'], instance_ref2['id'])
- self.assertEqual(address_v6,
- utils.to_global_ipv6(
- network_ref['cidr_v6'],
- instance_ref['mac_address']))
- self._deallocate_address(0, address)
- db.instance_destroy(context.get_admin_context(),
- instance_ref['id'])
-
- def test_public_network_association(self):
- """Makes sure that we can allocaate a public ip"""
- # TODO(vish): better way of adding floating ips
- self.context._project = self.projects[0]
- self.context.project_id = self.projects[0].id
- pubnet = IPy.IP(flags.FLAGS.floating_range)
- address = str(pubnet[0])
- try:
- db.floating_ip_get_by_address(context.get_admin_context(), address)
- except exception.NotFound:
- db.floating_ip_create(context.get_admin_context(),
- {'address': address,
- 'host': FLAGS.host})
- float_addr = self.network.allocate_floating_ip(self.context,
- self.projects[0].id)
- fix_addr = self._create_address(0)
- lease_ip(fix_addr)
- self.assertEqual(float_addr, str(pubnet[0]))
- self.network.associate_floating_ip(self.context, float_addr, fix_addr)
- address = db.instance_get_floating_address(context.get_admin_context(),
- self.instance_id)
- self.assertEqual(address, float_addr)
- self.network.disassociate_floating_ip(self.context, float_addr)
- address = db.instance_get_floating_address(context.get_admin_context(),
- self.instance_id)
- self.assertEqual(address, None)
- self.network.deallocate_floating_ip(self.context, float_addr)
- self.network.deallocate_fixed_ip(self.context, fix_addr)
- release_ip(fix_addr)
- db.floating_ip_destroy(context.get_admin_context(), float_addr)
-
- def test_allocate_deallocate_fixed_ip(self):
- """Makes sure that we can allocate and deallocate a fixed ip"""
- address = self._create_address(0)
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
- lease_ip(address)
- self._deallocate_address(0, address)
-
- # Doesn't go away until it's dhcp released
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
-
- release_ip(address)
- self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
-
- def test_side_effects(self):
- """Ensures allocating and releasing has no side effects"""
- address = self._create_address(0)
- address2 = self._create_address(1, self.instance2_id)
-
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
- self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
- self.assertFalse(is_allocated_in_project(address, self.projects[1].id))
-
- # Addresses are allocated before they're issued
- lease_ip(address)
- lease_ip(address2)
-
- self._deallocate_address(0, address)
- release_ip(address)
- self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
-
- # First address release shouldn't affect the second
- self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
-
- self._deallocate_address(1, address2)
- release_ip(address2)
- self.assertFalse(is_allocated_in_project(address2,
- self.projects[1].id))
-
- def test_subnet_edge(self):
- """Makes sure that private ips don't overlap"""
- first = self._create_address(0)
- lease_ip(first)
- instance_ids = []
- for i in range(1, FLAGS.num_networks):
- instance_ref = self._create_instance(i, mac=utils.generate_mac())
- instance_ids.append(instance_ref['id'])
- address = self._create_address(i, instance_ref['id'])
- instance_ref = self._create_instance(i, mac=utils.generate_mac())
- instance_ids.append(instance_ref['id'])
- address2 = self._create_address(i, instance_ref['id'])
- instance_ref = self._create_instance(i, mac=utils.generate_mac())
- instance_ids.append(instance_ref['id'])
- address3 = self._create_address(i, instance_ref['id'])
- lease_ip(address)
- lease_ip(address2)
- lease_ip(address3)
- self.context._project = self.projects[i]
- self.context.project_id = self.projects[i].id
- self.assertFalse(is_allocated_in_project(address,
- self.projects[0].id))
- self.assertFalse(is_allocated_in_project(address2,
- self.projects[0].id))
- self.assertFalse(is_allocated_in_project(address3,
- self.projects[0].id))
- self.network.deallocate_fixed_ip(self.context, address)
- self.network.deallocate_fixed_ip(self.context, address2)
- self.network.deallocate_fixed_ip(self.context, address3)
- release_ip(address)
- release_ip(address2)
- release_ip(address3)
- for instance_id in instance_ids:
- db.instance_destroy(context.get_admin_context(), instance_id)
- self.context._project = self.projects[0]
- self.context.project_id = self.projects[0].id
- self.network.deallocate_fixed_ip(self.context, first)
- self._deallocate_address(0, first)
- release_ip(first)
-
- def test_vpn_ip_and_port_looks_valid(self):
- """Ensure the vpn ip and port are reasonable"""
- self.assert_(self.projects[0].vpn_ip)
- self.assert_(self.projects[0].vpn_port >= FLAGS.vpn_start)
- self.assert_(self.projects[0].vpn_port <= FLAGS.vpn_start +
- FLAGS.num_networks)
-
- def test_too_many_networks(self):
- """Ensure error is raised if we run out of networks"""
- projects = []
- networks_left = (FLAGS.num_networks -
- db.network_count(context.get_admin_context()))
- for i in range(networks_left):
- project = self.manager.create_project('many%s' % i, self.user)
- projects.append(project)
- db.project_get_network(context.get_admin_context(), project.id)
- project = self.manager.create_project('last', self.user)
- projects.append(project)
- self.assertRaises(db.NoMoreNetworks,
- db.project_get_network,
- context.get_admin_context(),
- project.id)
- for project in projects:
- self.manager.delete_project(project)
-
- def test_ips_are_reused(self):
- """Makes sure that ip addresses that are deallocated get reused"""
- address = self._create_address(0)
- lease_ip(address)
- self.network.deallocate_fixed_ip(self.context, address)
- release_ip(address)
-
- address2 = self._create_address(0)
- self.assertEqual(address, address2)
- lease_ip(address)
- self.network.deallocate_fixed_ip(self.context, address2)
- release_ip(address)
-
- def test_available_ips(self):
- """Make sure the number of available ips for the network is correct
-
- The number of available IP addresses depends on the test
- environment's setup.
-
- Network size is set in test fixture's setUp method.
-
- There are ips reserved at the bottom and top of the range.
- services (network, gateway, CloudPipe, broadcast)
- """
- network = db.project_get_network(context.get_admin_context(),
- self.projects[0].id)
- net_size = flags.FLAGS.network_size
- admin_context = context.get_admin_context()
- total_ips = (db.network_count_available_ips(admin_context,
- network['id']) +
- db.network_count_reserved_ips(admin_context,
- network['id']) +
- db.network_count_allocated_ips(admin_context,
- network['id']))
- self.assertEqual(total_ips, net_size)
-
- def test_too_many_addresses(self):
- """Test for a NoMoreAddresses exception when all fixed ips are used.
- """
- admin_context = context.get_admin_context()
- network = db.project_get_network(admin_context, self.projects[0].id)
- num_available_ips = db.network_count_available_ips(admin_context,
- network['id'])
- addresses = []
- instance_ids = []
- for i in range(num_available_ips):
- instance_ref = self._create_instance(0)
- instance_ids.append(instance_ref['id'])
- address = self._create_address(0, instance_ref['id'])
- addresses.append(address)
- lease_ip(address)
-
- ip_count = db.network_count_available_ips(context.get_admin_context(),
- network['id'])
- self.assertEqual(ip_count, 0)
- self.assertRaises(db.NoMoreAddresses,
- self.network.allocate_fixed_ip,
- self.context,
- 'foo')
-
- for i in range(num_available_ips):
- self.network.deallocate_fixed_ip(self.context, addresses[i])
- release_ip(addresses[i])
- db.instance_destroy(context.get_admin_context(), instance_ids[i])
- ip_count = db.network_count_available_ips(context.get_admin_context(),
- network['id'])
- self.assertEqual(ip_count, num_available_ips)
-
-
-def is_allocated_in_project(address, project_id):
- """Returns true if address is in specified project"""
- project_net = db.project_get_network(context.get_admin_context(),
- project_id)
- network = db.fixed_ip_get_network(context.get_admin_context(), address)
- instance = db.fixed_ip_get_instance(context.get_admin_context(), address)
- # instance exists until release
- return instance is not None and network['id'] == project_net['id']
-
-
-def binpath(script):
- """Returns the absolute path to a script in bin"""
- return os.path.abspath(os.path.join(__file__, "../../../bin", script))
-
-
-def lease_ip(private_ip):
- """Run add command on dhcpbridge"""
- network_ref = db.fixed_ip_get_network(context.get_admin_context(),
- private_ip)
- instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
- private_ip)
- cmd = "%s add %s %s fake" % (binpath('nova-dhcpbridge'),
- instance_ref['mac_address'],
- private_ip)
- env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
- 'TESTING': '1',
- 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
- (out, err) = utils.execute(cmd, addl_env=env)
- LOG.debug("ISSUE_IP: %s, %s ", out, err)
-
-
-def release_ip(private_ip):
- """Run del command on dhcpbridge"""
- network_ref = db.fixed_ip_get_network(context.get_admin_context(),
- private_ip)
- instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
- private_ip)
- cmd = "%s del %s %s fake" % (binpath('nova-dhcpbridge'),
- instance_ref['mac_address'],
- private_ip)
- env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
- 'TESTING': '1',
- 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
- (out, err) = utils.execute(cmd, addl_env=env)
- LOG.debug("RELEASE_IP: %s, %s ", out, err)
diff --git a/nova/tests/test_vlan_network.py b/nova/tests/test_vlan_network.py
new file mode 100644
index 000000000..be39313bb
--- /dev/null
+++ b/nova/tests/test_vlan_network.py
@@ -0,0 +1,373 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# 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.
+"""
+Unit Tests for network code
+"""
+import IPy
+import os
+
+from nova import context
+from nova import db
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import test
+from nova import utils
+from nova.auth import manager
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.network')
+
+
+class VlanNetworkTestCase(test.TestCase):
+ """Test cases for network code"""
+ def setUp(self):
+ super(VlanNetworkTestCase, self).setUp()
+ # NOTE(vish): if you change these flags, make sure to change the
+ # flags in the corresponding section in nova-dhcpbridge
+ self.flags(connection_type='fake',
+ fake_call=True,
+ fake_network=True)
+ self.manager = manager.AuthManager()
+ self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
+ self.projects = []
+ self.network = utils.import_object(FLAGS.network_manager)
+ self.context = context.RequestContext(project=None, user=self.user)
+ for i in range(FLAGS.num_networks):
+ name = 'project%s' % i
+ project = self.manager.create_project(name, 'netuser', name)
+ self.projects.append(project)
+ # create the necessary network data for the project
+ user_context = context.RequestContext(project=self.projects[i],
+ user=self.user)
+ host = self.network.get_network_host(user_context.elevated())
+ instance_ref = self._create_instance(0)
+ self.instance_id = instance_ref['id']
+ instance_ref = self._create_instance(1)
+ self.instance2_id = instance_ref['id']
+
+ def tearDown(self):
+ # TODO(termie): this should really be instantiating clean datastores
+ # in between runs, one failure kills all the tests
+ db.instance_destroy(context.get_admin_context(), self.instance_id)
+ db.instance_destroy(context.get_admin_context(), self.instance2_id)
+ for project in self.projects:
+ self.manager.delete_project(project)
+ self.manager.delete_user(self.user)
+ super(VlanNetworkTestCase, self).tearDown()
+
+ def run(self, result=None):
+ if(FLAGS.network_manager == 'nova.network.manager.VlanManager'):
+ super(VlanNetworkTestCase, self).run(result)
+
+ def _create_instance(self, project_num, mac=None):
+ if not mac:
+ mac = utils.generate_mac()
+ project = self.projects[project_num]
+ self.context._project = project
+ self.context.project_id = project.id
+ return db.instance_create(self.context,
+ {'project_id': project.id,
+ 'mac_address': mac})
+
+ def _create_address(self, project_num, instance_id=None):
+ """Create an address in given project num"""
+ if instance_id is None:
+ instance_id = self.instance_id
+ self.context._project = self.projects[project_num]
+ self.context.project_id = self.projects[project_num].id
+ return self.network.allocate_fixed_ip(self.context, instance_id)
+
+ def _deallocate_address(self, project_num, address):
+ self.context._project = self.projects[project_num]
+ self.context.project_id = self.projects[project_num].id
+ self.network.deallocate_fixed_ip(self.context, address)
+
+ def test_private_ipv6(self):
+ """Make sure ipv6 is OK"""
+ if FLAGS.use_ipv6:
+ instance_ref = self._create_instance(0)
+ address = self._create_address(0, instance_ref['id'])
+ network_ref = db.project_get_network(
+ context.get_admin_context(),
+ self.context.project_id)
+ address_v6 = db.instance_get_fixed_address_v6(
+ context.get_admin_context(),
+ instance_ref['id'])
+ self.assertEqual(instance_ref['mac_address'],
+ utils.to_mac(address_v6))
+ instance_ref2 = db.fixed_ip_get_instance_v6(
+ context.get_admin_context(),
+ address_v6)
+ self.assertEqual(instance_ref['id'], instance_ref2['id'])
+ self.assertEqual(address_v6,
+ utils.to_global_ipv6(
+ network_ref['cidr_v6'],
+ instance_ref['mac_address']))
+ self._deallocate_address(0, address)
+ db.instance_destroy(context.get_admin_context(),
+ instance_ref['id'])
+
+ def test_public_network_association(self):
+ """Makes sure that we can allocaate a public ip"""
+ # TODO(vish): better way of adding floating ips
+ self.context._project = self.projects[0]
+ self.context.project_id = self.projects[0].id
+ pubnet = IPy.IP(flags.FLAGS.floating_range)
+ address = str(pubnet[0])
+ try:
+ db.floating_ip_get_by_address(context.get_admin_context(), address)
+ except exception.NotFound:
+ db.floating_ip_create(context.get_admin_context(),
+ {'address': address,
+ 'host': FLAGS.host})
+ float_addr = self.network.allocate_floating_ip(self.context,
+ self.projects[0].id)
+ fix_addr = self._create_address(0)
+ lease_ip(fix_addr)
+ self.assertEqual(float_addr, str(pubnet[0]))
+ self.network.associate_floating_ip(self.context, float_addr, fix_addr)
+ address = db.instance_get_floating_address(context.get_admin_context(),
+ self.instance_id)
+ self.assertEqual(address, float_addr)
+ self.network.disassociate_floating_ip(self.context, float_addr)
+ address = db.instance_get_floating_address(context.get_admin_context(),
+ self.instance_id)
+ self.assertEqual(address, None)
+ self.network.deallocate_floating_ip(self.context, float_addr)
+ self.network.deallocate_fixed_ip(self.context, fix_addr)
+ release_ip(fix_addr)
+ db.floating_ip_destroy(context.get_admin_context(), float_addr)
+
+ def test_allocate_deallocate_fixed_ip(self):
+ """Makes sure that we can allocate and deallocate a fixed ip"""
+ address = self._create_address(0)
+ self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+ lease_ip(address)
+ self._deallocate_address(0, address)
+
+ # Doesn't go away until it's dhcp released
+ self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+
+ release_ip(address)
+ self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+
+ def test_side_effects(self):
+ """Ensures allocating and releasing has no side effects"""
+ address = self._create_address(0)
+ address2 = self._create_address(1, self.instance2_id)
+
+ self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+ self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
+ self.assertFalse(is_allocated_in_project(address, self.projects[1].id))
+
+ # Addresses are allocated before they're issued
+ lease_ip(address)
+ lease_ip(address2)
+
+ self._deallocate_address(0, address)
+ release_ip(address)
+ self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+
+ # First address release shouldn't affect the second
+ self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
+
+ self._deallocate_address(1, address2)
+ release_ip(address2)
+ self.assertFalse(is_allocated_in_project(address2,
+ self.projects[1].id))
+
+ def test_subnet_edge(self):
+ """Makes sure that private ips don't overlap"""
+ first = self._create_address(0)
+ lease_ip(first)
+ instance_ids = []
+ for i in range(1, FLAGS.num_networks):
+ instance_ref = self._create_instance(i, mac=utils.generate_mac())
+ instance_ids.append(instance_ref['id'])
+ address = self._create_address(i, instance_ref['id'])
+ instance_ref = self._create_instance(i, mac=utils.generate_mac())
+ instance_ids.append(instance_ref['id'])
+ address2 = self._create_address(i, instance_ref['id'])
+ instance_ref = self._create_instance(i, mac=utils.generate_mac())
+ instance_ids.append(instance_ref['id'])
+ address3 = self._create_address(i, instance_ref['id'])
+ lease_ip(address)
+ lease_ip(address2)
+ lease_ip(address3)
+ self.context._project = self.projects[i]
+ self.context.project_id = self.projects[i].id
+ self.assertFalse(is_allocated_in_project(address,
+ self.projects[0].id))
+ self.assertFalse(is_allocated_in_project(address2,
+ self.projects[0].id))
+ self.assertFalse(is_allocated_in_project(address3,
+ self.projects[0].id))
+ self.network.deallocate_fixed_ip(self.context, address)
+ self.network.deallocate_fixed_ip(self.context, address2)
+ self.network.deallocate_fixed_ip(self.context, address3)
+ release_ip(address)
+ release_ip(address2)
+ release_ip(address3)
+ for instance_id in instance_ids:
+ db.instance_destroy(context.get_admin_context(), instance_id)
+ self.context._project = self.projects[0]
+ self.context.project_id = self.projects[0].id
+ self.network.deallocate_fixed_ip(self.context, first)
+ self._deallocate_address(0, first)
+ release_ip(first)
+
+ def test_vpn_ip_and_port_looks_valid(self):
+ """Ensure the vpn ip and port are reasonable"""
+ self.assert_(self.projects[0].vpn_ip)
+ self.assert_(self.projects[0].vpn_port >= FLAGS.vpn_start)
+ self.assert_(self.projects[0].vpn_port <= FLAGS.vpn_start +
+ FLAGS.num_networks)
+
+ def test_too_many_networks(self):
+ """Ensure error is raised if we run out of networks"""
+ projects = []
+ networks_left = (FLAGS.num_networks -
+ db.network_count(context.get_admin_context()))
+ for i in range(networks_left):
+ project = self.manager.create_project('many%s' % i, self.user)
+ projects.append(project)
+ db.project_get_network(context.get_admin_context(), project.id)
+ project = self.manager.create_project('last', self.user)
+ projects.append(project)
+ self.assertRaises(db.NoMoreNetworks,
+ db.project_get_network,
+ context.get_admin_context(),
+ project.id)
+ for project in projects:
+ self.manager.delete_project(project)
+
+ def test_ips_are_reused(self):
+ """Makes sure that ip addresses that are deallocated get reused"""
+ address = self._create_address(0)
+ lease_ip(address)
+ self.network.deallocate_fixed_ip(self.context, address)
+ release_ip(address)
+
+ address2 = self._create_address(0)
+ self.assertEqual(address, address2)
+ lease_ip(address)
+ self.network.deallocate_fixed_ip(self.context, address2)
+ release_ip(address)
+
+ def test_available_ips(self):
+ """Make sure the number of available ips for the network is correct
+
+ The number of available IP addresses depends on the test
+ environment's setup.
+
+ Network size is set in test fixture's setUp method.
+
+ There are ips reserved at the bottom and top of the range.
+ services (network, gateway, CloudPipe, broadcast)
+ """
+ network = db.project_get_network(context.get_admin_context(),
+ self.projects[0].id)
+ net_size = flags.FLAGS.network_size
+ admin_context = context.get_admin_context()
+ total_ips = (db.network_count_available_ips(admin_context,
+ network['id']) +
+ db.network_count_reserved_ips(admin_context,
+ network['id']) +
+ db.network_count_allocated_ips(admin_context,
+ network['id']))
+ self.assertEqual(total_ips, net_size)
+
+ def test_too_many_addresses(self):
+ """Test for a NoMoreAddresses exception when all fixed ips are used.
+ """
+ admin_context = context.get_admin_context()
+ network = db.project_get_network(admin_context, self.projects[0].id)
+ num_available_ips = db.network_count_available_ips(admin_context,
+ network['id'])
+ addresses = []
+ instance_ids = []
+ for i in range(num_available_ips):
+ instance_ref = self._create_instance(0)
+ instance_ids.append(instance_ref['id'])
+ address = self._create_address(0, instance_ref['id'])
+ addresses.append(address)
+ lease_ip(address)
+
+ ip_count = db.network_count_available_ips(context.get_admin_context(),
+ network['id'])
+ self.assertEqual(ip_count, 0)
+ self.assertRaises(db.NoMoreAddresses,
+ self.network.allocate_fixed_ip,
+ self.context,
+ 'foo')
+
+ for i in range(num_available_ips):
+ self.network.deallocate_fixed_ip(self.context, addresses[i])
+ release_ip(addresses[i])
+ db.instance_destroy(context.get_admin_context(), instance_ids[i])
+ ip_count = db.network_count_available_ips(context.get_admin_context(),
+ network['id'])
+ self.assertEqual(ip_count, num_available_ips)
+
+
+def is_allocated_in_project(address, project_id):
+ """Returns true if address is in specified project"""
+ project_net = db.project_get_network(context.get_admin_context(),
+ project_id)
+ network = db.fixed_ip_get_network(context.get_admin_context(), address)
+ instance = db.fixed_ip_get_instance(context.get_admin_context(), address)
+ # instance exists until release
+ return instance is not None and network['id'] == project_net['id']
+
+
+def binpath(script):
+ """Returns the absolute path to a script in bin"""
+ return os.path.abspath(os.path.join(__file__, "../../../bin", script))
+
+
+def lease_ip(private_ip):
+ """Run add command on dhcpbridge"""
+ network_ref = db.fixed_ip_get_network(context.get_admin_context(),
+ private_ip)
+ instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
+ private_ip)
+ cmd = "%s add %s %s fake" % (binpath('nova-dhcpbridge'),
+ instance_ref['mac_address'],
+ private_ip)
+ env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
+ 'TESTING': '1',
+ 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
+ (out, err) = utils.execute(cmd, addl_env=env)
+ LOG.debug("ISSUE_IP: %s, %s ", out, err)
+
+
+def release_ip(private_ip):
+ """Run del command on dhcpbridge"""
+ network_ref = db.fixed_ip_get_network(context.get_admin_context(),
+ private_ip)
+ instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
+ private_ip)
+ cmd = "%s del %s %s fake" % (binpath('nova-dhcpbridge'),
+ instance_ref['mac_address'],
+ private_ip)
+ env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
+ 'TESTING': '1',
+ 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
+ (out, err) = utils.execute(cmd, addl_env=env)
+ LOG.debug("RELEASE_IP: %s, %s ", out, err)
--
cgit
From a74bf3381ada34f35c43d6f307fbae9abecfb255 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Tue, 8 Mar 2011 10:30:48 -0800
Subject: abstracted network code in the base class for flat and vlan
---
nova/network/manager.py | 8 +-
nova/tests/network/__init__.py | 47 +++++++++
nova/tests/network/base.py | 154 ++++++++++++++++++++++++++++++
nova/tests/test_flat_network.py | 147 ++++------------------------
nova/tests/test_vlan_network.py | 205 ++++++++--------------------------------
5 files changed, 259 insertions(+), 302 deletions(-)
create mode 100644 nova/tests/network/__init__.py
create mode 100644 nova/tests/network/base.py
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 686ab9732..670ff55fd 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -404,9 +404,11 @@ class FlatManager(NetworkManager):
net = {}
net['injected'] = FLAGS.flat_injected
net['dns'] = FLAGS.flat_network_dns
- if(FLAGS.use_ipv6):
- net['gateway_v6'] = \
- utils.get_my_linklocal(FLAGS.flat_network_bridge)
+ if not FLAGS.fake_network:
+ if(FLAGS.use_ipv6):
+ net['gateway_v6'] = \
+ utils.get_my_linklocal(
+ FLAGS.flat_network_bridge)
self.db.network_update(context, network_id, net)
def allocate_floating_ip(self, context, project_id):
diff --git a/nova/tests/network/__init__.py b/nova/tests/network/__init__.py
new file mode 100644
index 000000000..e51065983
--- /dev/null
+++ b/nova/tests/network/__init__.py
@@ -0,0 +1,47 @@
+import os
+
+from nova import context
+from nova import db
+from nova import flags
+from nova import log as logging
+from nova import utils
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.network')
+
+
+def binpath(script):
+ """Returns the absolute path to a script in bin"""
+ return os.path.abspath(os.path.join(__file__, "../../../../bin", script))
+
+
+def lease_ip(private_ip):
+ """Run add command on dhcpbridge"""
+ network_ref = db.fixed_ip_get_network(context.get_admin_context(),
+ private_ip)
+ instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
+ private_ip)
+ cmd = "%s add %s %s fake" % (binpath('nova-dhcpbridge'),
+ instance_ref['mac_address'],
+ private_ip)
+ env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
+ 'TESTING': '1',
+ 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
+ (out, err) = utils.execute(cmd, addl_env=env)
+ LOG.debug("ISSUE_IP: %s, %s ", out, err)
+
+
+def release_ip(private_ip):
+ """Run del command on dhcpbridge"""
+ network_ref = db.fixed_ip_get_network(context.get_admin_context(),
+ private_ip)
+ instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
+ private_ip)
+ cmd = "%s del %s %s fake" % (binpath('nova-dhcpbridge'),
+ instance_ref['mac_address'],
+ private_ip)
+ env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
+ 'TESTING': '1',
+ 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
+ (out, err) = utils.execute(cmd, addl_env=env)
+ LOG.debug("RELEASE_IP: %s, %s ", out, err)
diff --git a/nova/tests/network/base.py b/nova/tests/network/base.py
new file mode 100644
index 000000000..2dd8178ff
--- /dev/null
+++ b/nova/tests/network/base.py
@@ -0,0 +1,154 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# 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.
+"""
+Base class of Unit Tests for all network models
+"""
+import IPy
+import os
+
+from nova import context
+from nova import db
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import test
+from nova import utils
+from nova.auth import manager
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.network')
+
+
+class NetworkTestCase(test.TestCase):
+ """Test cases for network code"""
+ def setUp(self):
+ super(NetworkTestCase, self).setUp()
+ # NOTE(vish): if you change these flags, make sure to change the
+ # flags in the corresponding section in nova-dhcpbridge
+ self.flags(connection_type='fake',
+ fake_call=True,
+ fake_network=True)
+ self.manager = manager.AuthManager()
+ self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
+ self.projects = []
+ self.network = utils.import_object(FLAGS.network_manager)
+ self.context = context.RequestContext(project=None, user=self.user)
+ for i in range(FLAGS.num_networks):
+ name = 'project%s' % i
+ project = self.manager.create_project(name, 'netuser', name)
+ self.projects.append(project)
+ # create the necessary network data for the project
+ user_context = context.RequestContext(project=self.projects[i],
+ user=self.user)
+ host = self.network.get_network_host(user_context.elevated())
+ instance_ref = self._create_instance(0)
+ self.instance_id = instance_ref['id']
+ instance_ref = self._create_instance(1)
+ self.instance2_id = instance_ref['id']
+
+ def tearDown(self):
+ # TODO(termie): this should really be instantiating clean datastores
+ # in between runs, one failure kills all the tests
+ db.instance_destroy(context.get_admin_context(), self.instance_id)
+ db.instance_destroy(context.get_admin_context(), self.instance2_id)
+ for project in self.projects:
+ self.manager.delete_project(project)
+ self.manager.delete_user(self.user)
+ super(NetworkTestCase, self).tearDown()
+
+ def _create_instance(self, project_num, mac=None):
+ if not mac:
+ mac = utils.generate_mac()
+ project = self.projects[project_num]
+ self.context._project = project
+ self.context.project_id = project.id
+ return db.instance_create(self.context,
+ {'project_id': project.id,
+ 'mac_address': mac})
+
+ def _create_address(self, project_num, instance_id=None):
+ """Create an address in given project num"""
+ if instance_id is None:
+ instance_id = self.instance_id
+ self.context._project = self.projects[project_num]
+ self.context.project_id = self.projects[project_num].id
+ return self.network.allocate_fixed_ip(self.context, instance_id)
+
+ def _deallocate_address(self, project_num, address):
+ self.context._project = self.projects[project_num]
+ self.context.project_id = self.projects[project_num].id
+ self.network.deallocate_fixed_ip(self.context, address)
+
+ def _is_allocated_in_project(self, address, project_id):
+ """Returns true if address is in specified project"""
+ project_net = db.network_get_by_bridge(context.get_admin_context(),
+ FLAGS.flat_network_bridge)
+ network = db.fixed_ip_get_network(context.get_admin_context(),
+ address)
+ instance = db.fixed_ip_get_instance(context.get_admin_context(),
+ address)
+ # instance exists until release
+ return instance is not None and network['id'] == project_net['id']
+
+ def test_private_ipv6(self):
+ """Make sure ipv6 is OK"""
+ if FLAGS.use_ipv6:
+ instance_ref = self._create_instance(0)
+ address = self._create_address(0, instance_ref['id'])
+ network_ref = db.project_get_network(
+ context.get_admin_context(),
+ self.context.project_id)
+ address_v6 = db.instance_get_fixed_address_v6(
+ context.get_admin_context(),
+ instance_ref['id'])
+ self.assertEqual(instance_ref['mac_address'],
+ utils.to_mac(address_v6))
+ instance_ref2 = db.fixed_ip_get_instance_v6(
+ context.get_admin_context(),
+ address_v6)
+ self.assertEqual(instance_ref['id'], instance_ref2['id'])
+ self.assertEqual(address_v6,
+ utils.to_global_ipv6(
+ network_ref['cidr_v6'],
+ instance_ref['mac_address']))
+ self._deallocate_address(0, address)
+ db.instance_destroy(context.get_admin_context(),
+ instance_ref['id'])
+
+ def test_available_ips(self):
+ """Make sure the number of available ips for the network is correct
+
+ The number of available IP addresses depends on the test
+ environment's setup.
+
+ Network size is set in test fixture's setUp method.
+
+ There are ips reserved at the bottom and top of the range.
+ services (network, gateway, CloudPipe, broadcast)
+ """
+ network = db.project_get_network(context.get_admin_context(),
+ self.projects[0].id)
+ net_size = flags.FLAGS.network_size
+ admin_context = context.get_admin_context()
+ total_ips = (db.network_count_available_ips(admin_context,
+ network['id']) +
+ db.network_count_reserved_ips(admin_context,
+ network['id']) +
+ db.network_count_allocated_ips(admin_context,
+ network['id']))
+ self.assertEqual(total_ips, net_size)
diff --git a/nova/tests/test_flat_network.py b/nova/tests/test_flat_network.py
index 91a49920d..a9a934158 100644
--- a/nova/tests/test_flat_network.py
+++ b/nova/tests/test_flat_network.py
@@ -30,96 +30,15 @@ from nova import log as logging
from nova import test
from nova import utils
from nova.auth import manager
+from nova.tests.network import base
+
FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.tests.network')
-class FlatNetworkTestCase(test.TestCase):
+class FlatNetworkTestCase(base.NetworkTestCase):
"""Test cases for network code"""
- def setUp(self):
- super(FlatNetworkTestCase, self).setUp()
- # NOTE(vish): if you change these flags, make sure to change the
- # flags in the corresponding section in nova-dhcpbridge
- self.flags(connection_type='fake',
- fake_call=True,
- fake_network=True)
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
- self.projects = []
- self.network = utils.import_object(FLAGS.network_manager)
- self.context = context.RequestContext(project=None, user=self.user)
- for i in range(5):
- name = 'project%s' % i
- project = self.manager.create_project(name, 'netuser', name)
- self.projects.append(project)
- # create the necessary network data for the project
- user_context = context.RequestContext(project=self.projects[i],
- user=self.user)
- host = self.network.get_network_host(user_context.elevated())
- instance_ref = self._create_instance(0)
- self.instance_id = instance_ref['id']
- instance_ref = self._create_instance(1)
- self.instance2_id = instance_ref['id']
-
- def tearDown(self):
- # TODO(termie): this should really be instantiating clean datastores
- # in between runs, one failure kills all the tests
- db.instance_destroy(context.get_admin_context(), self.instance_id)
- db.instance_destroy(context.get_admin_context(), self.instance2_id)
- for project in self.projects:
- self.manager.delete_project(project)
- self.manager.delete_user(self.user)
- super(FlatNetworkTestCase, self).tearDown()
-
- def _create_instance(self, project_num, mac=None):
- if not mac:
- mac = utils.generate_mac()
- project = self.projects[project_num]
- self.context._project = project
- self.context.project_id = project.id
- return db.instance_create(self.context,
- {'project_id': project.id,
- 'mac_address': mac})
-
- def _create_address(self, project_num, instance_id=None):
- """Create an address in given project num"""
- if instance_id is None:
- instance_id = self.instance_id
- self.context._project = self.projects[project_num]
- self.context.project_id = self.projects[project_num].id
- return self.network.allocate_fixed_ip(self.context, instance_id)
-
- def _deallocate_address(self, project_num, address):
- self.context._project = self.projects[project_num]
- self.context.project_id = self.projects[project_num].id
- self.network.deallocate_fixed_ip(self.context, address)
-
- def test_private_ipv6(self):
- """Make sure ipv6 is OK"""
- if FLAGS.use_ipv6:
- instance_ref = self._create_instance(0)
- address = self._create_address(0, instance_ref['id'])
- network_ref = db.project_get_network(
- context.get_admin_context(),
- self.context.project_id)
- address_v6 = db.instance_get_fixed_address_v6(
- context.get_admin_context(),
- instance_ref['id'])
- self.assertEqual(instance_ref['mac_address'],
- utils.to_mac(address_v6))
- instance_ref2 = db.fixed_ip_get_instance_v6(
- context.get_admin_context(),
- address_v6)
- self.assertEqual(instance_ref['id'], instance_ref2['id'])
- self.assertEqual(address_v6,
- utils.to_global_ipv6(
- network_ref['cidr_v6'],
- instance_ref['mac_address']))
- self._deallocate_address(0, address)
- db.instance_destroy(context.get_admin_context(),
- instance_ref['id'])
-
def test_public_network_association(self):
"""Makes sure that we can allocate a public ip"""
# TODO(vish): better way of adding floating ips
@@ -167,28 +86,34 @@ class FlatNetworkTestCase(test.TestCase):
def test_allocate_deallocate_fixed_ip(self):
"""Makes sure that we can allocate and deallocate a fixed ip"""
address = self._create_address(0)
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+ self.assertTrue(self._is_allocated_in_project(address,
+ self.projects[0].id))
self._deallocate_address(0, address)
# check if the fixed ip address is really deallocated
- self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+ self.assertFalse(self._is_allocated_in_project(address,
+ self.projects[0].id))
def test_side_effects(self):
"""Ensures allocating and releasing has no side effects"""
address = self._create_address(0)
address2 = self._create_address(1, self.instance2_id)
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
- self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
+ self.assertTrue(self._is_allocated_in_project(address,
+ self.projects[0].id))
+ self.assertTrue(self._is_allocated_in_project(address2,
+ self.projects[1].id))
self._deallocate_address(0, address)
- self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+ self.assertFalse(self._is_allocated_in_project(address,
+ self.projects[0].id))
# First address release shouldn't affect the second
- self.assertTrue(is_allocated_in_project(address2, self.projects[0].id))
+ self.assertTrue(self._is_allocated_in_project(address2,
+ self.projects[0].id))
self._deallocate_address(1, address2)
- self.assertFalse(is_allocated_in_project(address2,
+ self.assertFalse(self._is_allocated_in_project(address2,
self.projects[1].id))
def test_ips_are_reused(self):
@@ -201,29 +126,6 @@ class FlatNetworkTestCase(test.TestCase):
self.network.deallocate_fixed_ip(self.context, address2)
- def test_available_ips(self):
- """Make sure the number of available ips for the network is correct
-
- The number of available IP addresses depends on the test
- environment's setup.
-
- Network size is set in test fixture's setUp method.
-
- There are ips reserved at the bottom and top of the range.
- services (network, gateway, CloudPipe, broadcast)
- """
- network = db.project_get_network(context.get_admin_context(),
- self.projects[0].id)
- net_size = flags.FLAGS.network_size
- admin_context = context.get_admin_context()
- total_ips = (db.network_count_available_ips(admin_context,
- network['id']) +
- db.network_count_reserved_ips(admin_context,
- network['id']) +
- db.network_count_allocated_ips(admin_context,
- network['id']))
- self.assertEqual(total_ips, net_size)
-
def test_too_many_addresses(self):
"""Test for a NoMoreAddresses exception when all fixed ips are used.
"""
@@ -257,20 +159,3 @@ class FlatNetworkTestCase(test.TestCase):
def run(self, result=None):
if(FLAGS.network_manager == 'nova.network.manager.FlatManager'):
super(FlatNetworkTestCase, self).run(result)
-
-
-def is_allocated_in_project(address, project_id):
- """Returns true if address is in specified project"""
- #project_net = db.project_get_network(context.get_admin_context(),
- # project_id)
- project_net = db.network_get_by_bridge(context.get_admin_context(),
- FLAGS.flat_network_bridge)
- network = db.fixed_ip_get_network(context.get_admin_context(), address)
- instance = db.fixed_ip_get_instance(context.get_admin_context(), address)
- # instance exists until release
- return instance is not None and network['id'] == project_net['id']
-
-
-def binpath(script):
- """Returns the absolute path to a script in bin"""
- return os.path.abspath(os.path.join(__file__, "../../../bin", script))
diff --git a/nova/tests/test_vlan_network.py b/nova/tests/test_vlan_network.py
index be39313bb..f3478320b 100644
--- a/nova/tests/test_vlan_network.py
+++ b/nova/tests/test_vlan_network.py
@@ -29,100 +29,16 @@ from nova import log as logging
from nova import test
from nova import utils
from nova.auth import manager
+from nova.tests.network import base
+from nova.tests.network import binpath,\
+ lease_ip, release_ip
FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.tests.network')
-class VlanNetworkTestCase(test.TestCase):
+class VlanNetworkTestCase(base.NetworkTestCase):
"""Test cases for network code"""
- def setUp(self):
- super(VlanNetworkTestCase, self).setUp()
- # NOTE(vish): if you change these flags, make sure to change the
- # flags in the corresponding section in nova-dhcpbridge
- self.flags(connection_type='fake',
- fake_call=True,
- fake_network=True)
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
- self.projects = []
- self.network = utils.import_object(FLAGS.network_manager)
- self.context = context.RequestContext(project=None, user=self.user)
- for i in range(FLAGS.num_networks):
- name = 'project%s' % i
- project = self.manager.create_project(name, 'netuser', name)
- self.projects.append(project)
- # create the necessary network data for the project
- user_context = context.RequestContext(project=self.projects[i],
- user=self.user)
- host = self.network.get_network_host(user_context.elevated())
- instance_ref = self._create_instance(0)
- self.instance_id = instance_ref['id']
- instance_ref = self._create_instance(1)
- self.instance2_id = instance_ref['id']
-
- def tearDown(self):
- # TODO(termie): this should really be instantiating clean datastores
- # in between runs, one failure kills all the tests
- db.instance_destroy(context.get_admin_context(), self.instance_id)
- db.instance_destroy(context.get_admin_context(), self.instance2_id)
- for project in self.projects:
- self.manager.delete_project(project)
- self.manager.delete_user(self.user)
- super(VlanNetworkTestCase, self).tearDown()
-
- def run(self, result=None):
- if(FLAGS.network_manager == 'nova.network.manager.VlanManager'):
- super(VlanNetworkTestCase, self).run(result)
-
- def _create_instance(self, project_num, mac=None):
- if not mac:
- mac = utils.generate_mac()
- project = self.projects[project_num]
- self.context._project = project
- self.context.project_id = project.id
- return db.instance_create(self.context,
- {'project_id': project.id,
- 'mac_address': mac})
-
- def _create_address(self, project_num, instance_id=None):
- """Create an address in given project num"""
- if instance_id is None:
- instance_id = self.instance_id
- self.context._project = self.projects[project_num]
- self.context.project_id = self.projects[project_num].id
- return self.network.allocate_fixed_ip(self.context, instance_id)
-
- def _deallocate_address(self, project_num, address):
- self.context._project = self.projects[project_num]
- self.context.project_id = self.projects[project_num].id
- self.network.deallocate_fixed_ip(self.context, address)
-
- def test_private_ipv6(self):
- """Make sure ipv6 is OK"""
- if FLAGS.use_ipv6:
- instance_ref = self._create_instance(0)
- address = self._create_address(0, instance_ref['id'])
- network_ref = db.project_get_network(
- context.get_admin_context(),
- self.context.project_id)
- address_v6 = db.instance_get_fixed_address_v6(
- context.get_admin_context(),
- instance_ref['id'])
- self.assertEqual(instance_ref['mac_address'],
- utils.to_mac(address_v6))
- instance_ref2 = db.fixed_ip_get_instance_v6(
- context.get_admin_context(),
- address_v6)
- self.assertEqual(instance_ref['id'], instance_ref2['id'])
- self.assertEqual(address_v6,
- utils.to_global_ipv6(
- network_ref['cidr_v6'],
- instance_ref['mac_address']))
- self._deallocate_address(0, address)
- db.instance_destroy(context.get_admin_context(),
- instance_ref['id'])
-
def test_public_network_association(self):
"""Makes sure that we can allocaate a public ip"""
# TODO(vish): better way of adding floating ips
@@ -157,24 +73,30 @@ class VlanNetworkTestCase(test.TestCase):
def test_allocate_deallocate_fixed_ip(self):
"""Makes sure that we can allocate and deallocate a fixed ip"""
address = self._create_address(0)
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+ self.assertTrue(self._is_allocated_in_project(address,
+ self.projects[0].id))
lease_ip(address)
self._deallocate_address(0, address)
# Doesn't go away until it's dhcp released
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+ self.assertTrue(self._is_allocated_in_project(address,
+ self.projects[0].id))
release_ip(address)
- self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+ self.assertFalse(self._is_allocated_in_project(address,
+ self.projects[0].id))
def test_side_effects(self):
"""Ensures allocating and releasing has no side effects"""
address = self._create_address(0)
address2 = self._create_address(1, self.instance2_id)
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
- self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
- self.assertFalse(is_allocated_in_project(address, self.projects[1].id))
+ self.assertTrue(self._is_allocated_in_project(address,
+ self.projects[0].id))
+ self.assertTrue(self._is_allocated_in_project(address2,
+ self.projects[1].id))
+ self.assertFalse(self._is_allocated_in_project(address,
+ self.projects[1].id))
# Addresses are allocated before they're issued
lease_ip(address)
@@ -182,14 +104,16 @@ class VlanNetworkTestCase(test.TestCase):
self._deallocate_address(0, address)
release_ip(address)
- self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+ self.assertFalse(self._is_allocated_in_project(address,
+ self.projects[0].id))
# First address release shouldn't affect the second
- self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
+ self.assertTrue(self._is_allocated_in_project(address2,
+ self.projects[1].id))
self._deallocate_address(1, address2)
release_ip(address2)
- self.assertFalse(is_allocated_in_project(address2,
+ self.assertFalse(self._is_allocated_in_project(address2,
self.projects[1].id))
def test_subnet_edge(self):
@@ -212,11 +136,11 @@ class VlanNetworkTestCase(test.TestCase):
lease_ip(address3)
self.context._project = self.projects[i]
self.context.project_id = self.projects[i].id
- self.assertFalse(is_allocated_in_project(address,
+ self.assertFalse(self._is_allocated_in_project(address,
self.projects[0].id))
- self.assertFalse(is_allocated_in_project(address2,
+ self.assertFalse(self._is_allocated_in_project(address2,
self.projects[0].id))
- self.assertFalse(is_allocated_in_project(address3,
+ self.assertFalse(self._is_allocated_in_project(address3,
self.projects[0].id))
self.network.deallocate_fixed_ip(self.context, address)
self.network.deallocate_fixed_ip(self.context, address2)
@@ -270,29 +194,6 @@ class VlanNetworkTestCase(test.TestCase):
self.network.deallocate_fixed_ip(self.context, address2)
release_ip(address)
- def test_available_ips(self):
- """Make sure the number of available ips for the network is correct
-
- The number of available IP addresses depends on the test
- environment's setup.
-
- Network size is set in test fixture's setUp method.
-
- There are ips reserved at the bottom and top of the range.
- services (network, gateway, CloudPipe, broadcast)
- """
- network = db.project_get_network(context.get_admin_context(),
- self.projects[0].id)
- net_size = flags.FLAGS.network_size
- admin_context = context.get_admin_context()
- total_ips = (db.network_count_available_ips(admin_context,
- network['id']) +
- db.network_count_reserved_ips(admin_context,
- network['id']) +
- db.network_count_allocated_ips(admin_context,
- network['id']))
- self.assertEqual(total_ips, net_size)
-
def test_too_many_addresses(self):
"""Test for a NoMoreAddresses exception when all fixed ips are used.
"""
@@ -325,49 +226,17 @@ class VlanNetworkTestCase(test.TestCase):
network['id'])
self.assertEqual(ip_count, num_available_ips)
+ def _is_allocated_in_project(self, address, project_id):
+ """Returns true if address is in specified project"""
+ project_net = db.project_get_network(context.get_admin_context(),
+ project_id)
+ network = db.fixed_ip_get_network(context.get_admin_context(),
+ address)
+ instance = db.fixed_ip_get_instance(context.get_admin_context(),
+ address)
+ # instance exists until release
+ return instance is not None and network['id'] == project_net['id']
-def is_allocated_in_project(address, project_id):
- """Returns true if address is in specified project"""
- project_net = db.project_get_network(context.get_admin_context(),
- project_id)
- network = db.fixed_ip_get_network(context.get_admin_context(), address)
- instance = db.fixed_ip_get_instance(context.get_admin_context(), address)
- # instance exists until release
- return instance is not None and network['id'] == project_net['id']
-
-
-def binpath(script):
- """Returns the absolute path to a script in bin"""
- return os.path.abspath(os.path.join(__file__, "../../../bin", script))
-
-
-def lease_ip(private_ip):
- """Run add command on dhcpbridge"""
- network_ref = db.fixed_ip_get_network(context.get_admin_context(),
- private_ip)
- instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
- private_ip)
- cmd = "%s add %s %s fake" % (binpath('nova-dhcpbridge'),
- instance_ref['mac_address'],
- private_ip)
- env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
- 'TESTING': '1',
- 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
- (out, err) = utils.execute(cmd, addl_env=env)
- LOG.debug("ISSUE_IP: %s, %s ", out, err)
-
-
-def release_ip(private_ip):
- """Run del command on dhcpbridge"""
- network_ref = db.fixed_ip_get_network(context.get_admin_context(),
- private_ip)
- instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
- private_ip)
- cmd = "%s del %s %s fake" % (binpath('nova-dhcpbridge'),
- instance_ref['mac_address'],
- private_ip)
- env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
- 'TESTING': '1',
- 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
- (out, err) = utils.execute(cmd, addl_env=env)
- LOG.debug("RELEASE_IP: %s, %s ", out, err)
+ def run(self, result=None):
+ if(FLAGS.network_manager == 'nova.network.manager.VlanManager'):
+ super(VlanNetworkTestCase, self).run(result)
--
cgit
From 25bbe2afb0be3c79264376dd6a11e2bc97847702 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Thu, 10 Mar 2011 11:17:34 -0800
Subject: fixed formatting and redundant imports
---
nova/api/ec2/cloud.py | 6 +++---
.../db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py | 1 -
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 6ed6186be..c6309f03c 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -701,9 +701,9 @@ class CloudController(object):
fixed = instance['fixed_ip']
floating_addr = fixed['floating_ips'][0]['address']
if instance['fixed_ip']['network'] and 'use_v6' in kwargs:
- i['dnsNameV6'] = utils.to_global_ipv6(
- instance['fixed_ip']['network']['cidr_v6'],
- instance['mac_address'])
+ i['dnsNameV6'] = utils.to_global_ipv6(
+ instance['fixed_ip']['network']['cidr_v6'],
+ instance['mac_address'])
i['privateDnsName'] = fixed_addr
i['publicDnsName'] = floating_addr
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
index d14f52af1..b8514c439 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
@@ -12,7 +12,6 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-from lib2to3.fixer_util import String
from sqlalchemy import *
from migrate import *
--
cgit
From 998975651ac2f2df7a3f8af16d62d197f451180f Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Thu, 10 Mar 2011 13:53:27 -0800
Subject: Test login. Uncovered bug732866
---
nova/tests/integrated/integrated_helpers.py | 182 ++++++++++++++++++++++++++++
nova/tests/integrated/test_login.py | 77 ++++++++++++
2 files changed, 259 insertions(+)
create mode 100644 nova/tests/integrated/integrated_helpers.py
create mode 100644 nova/tests/integrated/test_login.py
diff --git a/nova/tests/integrated/integrated_helpers.py b/nova/tests/integrated/integrated_helpers.py
new file mode 100644
index 000000000..691ead6e1
--- /dev/null
+++ b/nova/tests/integrated/integrated_helpers.py
@@ -0,0 +1,182 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Justin Santa Barbara
+# All Rights Reserved.
+#
+# 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.
+
+"""
+Provides common functionality for integrated unit tests
+"""
+
+import random
+import string
+
+from nova import exception
+from nova import flags
+from nova import service
+from nova import test # For the flags
+from nova.auth import manager
+from nova.exception import Error
+from nova.log import logging
+from nova.tests.integrated.api import client
+
+
+FLAGS = flags.FLAGS
+
+LOG = logging.getLogger('nova.tests.integrated')
+
+
+def generate_random_alphanumeric(length):
+ """Creates a random alphanumeric string of specified length"""
+ return ''.join(random.choice(string.ascii_uppercase + string.digits)
+ for _x in range(length))
+
+
+def generate_random_numeric(length):
+ """Creates a random numeric string of specified length"""
+ return ''.join(random.choice(string.digits)
+ for _x in range(length))
+
+
+def generate_new_element(items, prefix, numeric=False):
+ """Creates a random string with prefix, that is not in 'items' list"""
+ while True:
+ if numeric:
+ candidate = prefix + generate_random_numeric(8)
+ else:
+ candidate = prefix + generate_random_alphanumeric(8)
+ if not candidate in items:
+ return candidate
+ print "Random collision on %s" % candidate
+
+
+class TestUser(object):
+ def __init__(self, name, secret, auth_url):
+ self.name = name
+ self.secret = secret
+ self.auth_url = auth_url
+
+ if not auth_url:
+ raise exception.Error("auth_url is required")
+ self.openstack_api = client.TestOpenStackClient(self.name,
+ self.secret,
+ self.auth_url)
+
+
+class IntegratedUnitTestContext(object):
+ __INSTANCE = None
+
+ def __init__(self):
+ self.auth_manager = manager.AuthManager()
+
+ self.wsgi_server = None
+ self.wsgi_apps = []
+ self.api_service = None
+
+ self.services = []
+ self.auth_url = None
+ self.project_name = None
+
+ self.setup()
+
+ def setup(self):
+ self._start_services()
+
+ self._create_test_user()
+
+ def _create_test_user(self):
+ self.test_user = self._create_unittest_user()
+
+ # No way to currently pass this through the OpenStack API
+ self.project_name = 'openstack'
+ self._configure_project(self.project_name, self.test_user)
+
+ def _start_services(self):
+ # WSGI shutdown broken :-(
+ if not self.api_service:
+ self._start_api_service()
+
+ def cleanup(self):
+ for service in self.services:
+ service.kill()
+ self.services = []
+ # TODO(justinsb): Shutdown WSGI & anything else we startup
+ # WSGI shutdown broken :-(
+ # self.wsgi_server.terminate()
+ # self.wsgi_server = None
+ self.test_user = None
+
+ def _create_unittest_user(self):
+ users = self.auth_manager.get_users()
+ user_names = [user.name for user in users]
+ auth_name = generate_new_element(user_names, 'unittest_user_')
+ auth_key = generate_random_alphanumeric(16)
+
+ # Right now there's a bug where auth_name and auth_key are reversed
+ auth_key = auth_name
+
+ self.auth_manager.create_user(auth_name, auth_name, auth_key, False)
+ return TestUser(auth_name, auth_key, self.auth_url)
+
+ def _configure_project(self, project_name, user):
+ projects = self.auth_manager.get_projects()
+ project_names = [project.name for project in projects]
+ if not project_name in project_names:
+ project = self.auth_manager.create_project(project_name,
+ user.name,
+ description=None,
+ member_users=None)
+ else:
+ self.auth_manager.add_to_project(user.name, project_name)
+
+ def _start_api_service(self):
+ api_service = service.ApiService.create()
+ api_service.start()
+
+ if not api_service:
+ raise Exception("API Service was None")
+
+ # WSGI shutdown broken :-(
+ #self.services.append(volume_service)
+ self.api_service = api_service
+
+ self.auth_url = 'http://localhost:8774/v1.0'
+
+ return api_service
+
+ # WSGI shutdown broken :-(
+ #@staticmethod
+ #def get():
+ # if not IntegratedUnitTestContext.__INSTANCE:
+ # IntegratedUnitTestContext.startup()
+ # #raise Error("Must call IntegratedUnitTestContext::startup")
+ # return IntegratedUnitTestContext.__INSTANCE
+
+ @staticmethod
+ def startup():
+ # Because WSGI shutdown is broken at the moment, we have to recycle
+ if IntegratedUnitTestContext.__INSTANCE:
+ #raise Error("Multiple calls to IntegratedUnitTestContext.startup")
+ IntegratedUnitTestContext.__INSTANCE.setup()
+ else:
+ IntegratedUnitTestContext.__INSTANCE = IntegratedUnitTestContext()
+ return IntegratedUnitTestContext.__INSTANCE
+
+ @staticmethod
+ def shutdown():
+ if not IntegratedUnitTestContext.__INSTANCE:
+ raise Error("Must call IntegratedUnitTestContext::startup")
+ IntegratedUnitTestContext.__INSTANCE.cleanup()
+ # WSGI shutdown broken :-(
+ #IntegratedUnitTestContext.__INSTANCE = None
diff --git a/nova/tests/integrated/test_login.py b/nova/tests/integrated/test_login.py
new file mode 100644
index 000000000..990dcaaf4
--- /dev/null
+++ b/nova/tests/integrated/test_login.py
@@ -0,0 +1,77 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Justin Santa Barbara
+# All Rights Reserved.
+#
+# 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 unittest
+
+from nova import flags
+from nova.log import logging
+from nova.tests.integrated import integrated_helpers
+from nova.tests.integrated.api import client
+
+LOG = logging.getLogger('nova.tests.integrated')
+
+FLAGS = flags.FLAGS
+FLAGS.verbose = True
+
+
+class LoginTest(unittest.TestCase):
+ def setUp(self):
+ super(LoginTest, self).setUp()
+ context = integrated_helpers.IntegratedUnitTestContext.startup()
+ self.user = context.test_user
+ self.api = self.user.openstack_api
+
+ def tearDown(self):
+ integrated_helpers.IntegratedUnitTestContext.shutdown()
+ super(LoginTest, self).tearDown()
+
+ def test_login(self):
+ """Simple check - we list flavors - so we know we're logged in"""
+ flavors = self.api.get_flavors()
+ for flavor in flavors:
+ LOG.debug(_("flavor: %s") % flavor)
+
+ def test_bad_login_password(self):
+ """Test that I get a 401 with a bad username"""
+ bad_credentials_api = client.TestOpenStackClient(self.user.name,
+ "notso_password",
+ self.user.auth_url)
+
+ self.assertRaises(client.OpenstackApiAuthenticationException,
+ bad_credentials_api.get_flavors)
+
+ def test_bad_login_username(self):
+ """Test that I get a 401 with a bad password"""
+ bad_credentials_api = client.TestOpenStackClient("notso_username",
+ self.user.secret,
+ self.user.auth_url)
+
+ self.assertRaises(client.OpenstackApiAuthenticationException,
+ bad_credentials_api.get_flavors)
+
+
+ def test_bad_login_both_bad(self):
+ """Test that I get a 401 with both bad username and bad password"""
+ bad_credentials_api = client.TestOpenStackClient("notso_username",
+ "notso_password",
+ self.user.auth_url)
+
+ self.assertRaises(client.OpenstackApiAuthenticationException,
+ bad_credentials_api.get_flavors)
+
+if __name__ == "__main__":
+ unittest.main()
--
cgit
From 3d6430ecd114daa21c72c3d215daaa94f0e87e62 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Thu, 10 Mar 2011 14:12:41 -0800
Subject: Re-removed the code that was deleted upstream but somehow didn't get
merged in. Bizarre!
---
nova/tests/integrated/api/client.py | 21 ---------------------
1 file changed, 21 deletions(-)
diff --git a/nova/tests/integrated/api/client.py b/nova/tests/integrated/api/client.py
index 0ce480ae7..da8d87e07 100644
--- a/nova/tests/integrated/api/client.py
+++ b/nova/tests/integrated/api/client.py
@@ -172,27 +172,6 @@ class TestOpenStackClient(object):
kwargs.setdefault('check_response_status', [200, 202])
return self.api_request(relative_uri, **kwargs)
- def get_keys_detail(self):
- return self.api_get('/keys/detail')['keys']
-
- def post_key(self, key):
- return self.api_post('/keys', key)['key']
-
- def delete_key(self, key_id):
- return self.api_delete('/keys/%s' % key_id)
-
- def get_volume(self, volume_id):
- return self.api_get('/volumes/%s' % volume_id)['volume']
-
- def get_volumes_detail(self):
- return self.api_get('/volumes/detail')['volumes']
-
- def post_volume(self, volume):
- return self.api_post('/volumes', volume)['volume']
-
- def delete_volume(self, volume_id):
- return self.api_delete('/volumes/%s' % volume_id)
-
def get_server(self, server_id):
return self.api_get('/servers/%s' % server_id)['server']
--
cgit
From 29bc4f5074ca3ada98a25a745077b998b4c5509c Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Thu, 10 Mar 2011 14:14:01 -0800
Subject: Pep8 / Style
---
nova/tests/integrated/test_login.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/tests/integrated/test_login.py b/nova/tests/integrated/test_login.py
index 990dcaaf4..e362f92d6 100644
--- a/nova/tests/integrated/test_login.py
+++ b/nova/tests/integrated/test_login.py
@@ -22,6 +22,7 @@ from nova.log import logging
from nova.tests.integrated import integrated_helpers
from nova.tests.integrated.api import client
+
LOG = logging.getLogger('nova.tests.integrated')
FLAGS = flags.FLAGS
@@ -63,7 +64,6 @@ class LoginTest(unittest.TestCase):
self.assertRaises(client.OpenstackApiAuthenticationException,
bad_credentials_api.get_flavors)
-
def test_bad_login_both_bad(self):
"""Test that I get a 401 with both bad username and bad password"""
bad_credentials_api = client.TestOpenStackClient("notso_username",
--
cgit
From 0d3e950ed4b0c8abbd619d4ac8724b4c3ce45bf1 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Thu, 10 Mar 2011 14:21:36 -0800
Subject: Document known bug numbers by the code which is degraded until the
bugs are fixed
---
nova/tests/integrated/api/client.py | 1 +
nova/tests/integrated/integrated_helpers.py | 6 ++++++
2 files changed, 7 insertions(+)
diff --git a/nova/tests/integrated/api/client.py b/nova/tests/integrated/api/client.py
index da8d87e07..6fba2930a 100644
--- a/nova/tests/integrated/api/client.py
+++ b/nova/tests/integrated/api/client.py
@@ -109,6 +109,7 @@ class TestOpenStackClient(object):
LOG.debug(_("%(auth_uri)s => code %(http_status)s") % locals())
# Until bug732866 is fixed, we can't check this properly...
+ # bug732866
#if http_status == 401:
if http_status != 204:
raise OpenstackApiAuthenticationException(response=response)
diff --git a/nova/tests/integrated/integrated_helpers.py b/nova/tests/integrated/integrated_helpers.py
index 691ead6e1..47093636e 100644
--- a/nova/tests/integrated/integrated_helpers.py
+++ b/nova/tests/integrated/integrated_helpers.py
@@ -104,6 +104,7 @@ class IntegratedUnitTestContext(object):
def _start_services(self):
# WSGI shutdown broken :-(
+ # bug731668
if not self.api_service:
self._start_api_service()
@@ -112,6 +113,7 @@ class IntegratedUnitTestContext(object):
service.kill()
self.services = []
# TODO(justinsb): Shutdown WSGI & anything else we startup
+ # bug731668
# WSGI shutdown broken :-(
# self.wsgi_server.terminate()
# self.wsgi_server = None
@@ -124,6 +126,7 @@ class IntegratedUnitTestContext(object):
auth_key = generate_random_alphanumeric(16)
# Right now there's a bug where auth_name and auth_key are reversed
+ # bug732907
auth_key = auth_name
self.auth_manager.create_user(auth_name, auth_name, auth_key, False)
@@ -156,6 +159,7 @@ class IntegratedUnitTestContext(object):
return api_service
# WSGI shutdown broken :-(
+ # bug731668
#@staticmethod
#def get():
# if not IntegratedUnitTestContext.__INSTANCE:
@@ -166,6 +170,7 @@ class IntegratedUnitTestContext(object):
@staticmethod
def startup():
# Because WSGI shutdown is broken at the moment, we have to recycle
+ # bug731668
if IntegratedUnitTestContext.__INSTANCE:
#raise Error("Multiple calls to IntegratedUnitTestContext.startup")
IntegratedUnitTestContext.__INSTANCE.setup()
@@ -179,4 +184,5 @@ class IntegratedUnitTestContext(object):
raise Error("Must call IntegratedUnitTestContext::startup")
IntegratedUnitTestContext.__INSTANCE.cleanup()
# WSGI shutdown broken :-(
+ # bug731668
#IntegratedUnitTestContext.__INSTANCE = None
--
cgit
From e891e48b63065a7218627289a908aece0f6a3730 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Fri, 11 Mar 2011 10:31:08 -0800
Subject: Made changes to xs-ipv6 code impacted because of addition of
flatmanger ipv6 support
---
nova/virt/xenapi/vmops.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 9ac83efb0..52d2652f9 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -617,9 +617,10 @@ class VMOps(object):
def ip6_dict(ip6):
return {
- "ip": ip6.addressV6,
- "netmask": ip6.netmaskV6,
- "gateway": ip6.gatewayV6,
+ "ip": utils.to_global_ipv6(network['cidr_v6'],
+ instance['mac_address']),
+ "netmask": network['netmask_v6'],
+ "gateway": network['gateway_v6'],
"enabled": "1"}
mac_id = instance.mac_address.replace(':', '')
--
cgit
From 5d0ca375e082c702b218c26f24d8009650a319a3 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Fri, 11 Mar 2011 14:36:31 -0800
Subject: Beginning of cleanup of FakeAuthManager
---
nova/tests/api/openstack/fakes.py | 41 +++++++++++++++++--------------
nova/tests/api/openstack/test_accounts.py | 4 +--
nova/tests/api/openstack/test_auth.py | 14 +++++------
nova/tests/api/openstack/test_users.py | 14 +++++------
4 files changed, 38 insertions(+), 35 deletions(-)
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py
index e50d11a3d..52ac80e3f 100644
--- a/nova/tests/api/openstack/fakes.py
+++ b/nova/tests/api/openstack/fakes.py
@@ -228,12 +228,14 @@ class FakeAuthDatabase(object):
class FakeAuthManager(object):
- auth_data = {}
+ #NOTE(justinsb): Accessing static variables through instances is FUBAR
+ #NOTE(justinsb): This should also be private!
+ auth_data = []
projects = {}
@classmethod
def clear_fakes(cls):
- cls.auth_data = {}
+ cls.auth_data = []
cls.projects = {}
@classmethod
@@ -246,34 +248,40 @@ class FakeAuthManager(object):
'test',
[]))
- def add_user(self, key, user):
- FakeAuthManager.auth_data[key] = user
+ def add_user(self, user):
+ FakeAuthManager.auth_data.append(user)
def get_users(self):
- return FakeAuthManager.auth_data.values()
+ return FakeAuthManager.auth_data
def get_user(self, uid):
- for k, v in FakeAuthManager.auth_data.iteritems():
- if v.id == uid:
- return v
+ for u in FakeAuthManager.auth_data:
+ if u.id == uid:
+ return u
+ return None
+
+ def get_user_from_access_key(self, key):
+ for u in FakeAuthManager.auth_data:
+ if u.access == key:
+ return u
return None
def delete_user(self, uid):
- for k, v in FakeAuthManager.auth_data.items():
- if v.id == uid:
- del FakeAuthManager.auth_data[k]
+ for u in FakeAuthManager.auth_data:
+ if u.id == uid:
+ FakeAuthManager.auth_data.remove(u)
return None
def create_user(self, name, access=None, secret=None, admin=False):
u = User(name, name, access, secret, admin)
- FakeAuthManager.auth_data[access] = u
+ FakeAuthManager.auth_data.append(u)
return u
def modify_user(self, user_id, access=None, secret=None, admin=None):
user = None
- for k, v in FakeAuthManager.auth_data.iteritems():
- if v.id == user_id:
- user = v
+ for u in FakeAuthManager.auth_data:
+ if u.id == user_id:
+ user = u
if user:
user.access = access
user.secret = secret
@@ -320,9 +328,6 @@ class FakeAuthManager(object):
if (user.id in p.member_ids) or
(user.id == p.project_manager_id)]
- def get_user_from_access_key(self, key):
- return FakeAuthManager.auth_data.get(key, None)
-
class FakeRateLimiter(object):
def __init__(self, application):
diff --git a/nova/tests/api/openstack/test_accounts.py b/nova/tests/api/openstack/test_accounts.py
index 60edce769..1bf49b33b 100644
--- a/nova/tests/api/openstack/test_accounts.py
+++ b/nova/tests/api/openstack/test_accounts.py
@@ -59,8 +59,8 @@ class AccountsTest(test.TestCase):
fakemgr = fakes.FakeAuthManager()
joeuser = User('guy1', 'guy1', 'acc1', 'fortytwo!', False)
superuser = User('guy2', 'guy2', 'acc2', 'swordfish', True)
- fakemgr.add_user(joeuser.access, joeuser)
- fakemgr.add_user(superuser.access, superuser)
+ fakemgr.add_user(joeuser)
+ fakemgr.add_user(superuser)
fakemgr.create_project('test1', joeuser)
fakemgr.create_project('test2', superuser)
diff --git a/nova/tests/api/openstack/test_auth.py b/nova/tests/api/openstack/test_auth.py
index aaaa4e415..84222f0f1 100644
--- a/nova/tests/api/openstack/test_auth.py
+++ b/nova/tests/api/openstack/test_auth.py
@@ -39,7 +39,7 @@ class Test(test.TestCase):
self.stubs.Set(nova.api.openstack.auth.AuthMiddleware,
'__init__', fakes.fake_auth_init)
self.stubs.Set(context, 'RequestContext', fakes.FakeRequestContext)
- fakes.FakeAuthManager.auth_data = {}
+ fakes.FakeAuthManager.clear_fakes()
fakes.FakeAuthDatabase.data = {}
fakes.stub_out_rate_limiting(self.stubs)
fakes.stub_out_networking(self.stubs)
@@ -51,7 +51,7 @@ class Test(test.TestCase):
def test_authorize_user(self):
f = fakes.FakeAuthManager()
- f.add_user('derp', nova.auth.manager.User(1, 'herp', None, None, None))
+ f.add_user(nova.auth.manager.User(1, 'herp', 'derp', None, None))
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-User'] = 'herp'
@@ -65,8 +65,8 @@ class Test(test.TestCase):
def test_authorize_token(self):
f = fakes.FakeAuthManager()
- u = nova.auth.manager.User(1, 'herp', None, None, None)
- f.add_user('derp', u)
+ u = nova.auth.manager.User(1, 'herp', 'derp', None, None)
+ f.add_user(u)
f.create_project('test', u)
req = webob.Request.blank('/v1.0/', {'HTTP_HOST': 'foo'})
@@ -167,7 +167,7 @@ class TestLimiter(test.TestCase):
self.stubs.Set(nova.api.openstack.auth.AuthMiddleware,
'__init__', fakes.fake_auth_init)
self.stubs.Set(context, 'RequestContext', fakes.FakeRequestContext)
- fakes.FakeAuthManager.auth_data = {}
+ fakes.FakeAuthManager.clear_fakes()
fakes.FakeAuthDatabase.data = {}
fakes.stub_out_networking(self.stubs)
@@ -178,8 +178,8 @@ class TestLimiter(test.TestCase):
def test_authorize_token(self):
f = fakes.FakeAuthManager()
- u = nova.auth.manager.User(1, 'herp', None, None, None)
- f.add_user('derp', u)
+ u = nova.auth.manager.User(1, 'herp', 'derp', None, None)
+ f.add_user(u)
f.create_project('test', u)
req = webob.Request.blank('/v1.0/')
diff --git a/nova/tests/api/openstack/test_users.py b/nova/tests/api/openstack/test_users.py
index 2dda4319b..a62db7efc 100644
--- a/nova/tests/api/openstack/test_users.py
+++ b/nova/tests/api/openstack/test_users.py
@@ -47,7 +47,7 @@ class UsersTest(test.TestCase):
fake_init)
self.stubs.Set(nova.api.openstack.users.Controller, '_check_admin',
fake_admin_check)
- fakes.FakeAuthManager.auth_data = {}
+ fakes.FakeAuthManager.clear_fakes()
fakes.FakeAuthManager.projects = dict(testacct=Project('testacct',
'testacct',
'guy1',
@@ -61,10 +61,8 @@ class UsersTest(test.TestCase):
self.allow_admin = FLAGS.allow_admin_api
FLAGS.allow_admin_api = True
fakemgr = fakes.FakeAuthManager()
- fakemgr.add_user('acc1', User('guy1', 'guy1', 'acc1',
- 'fortytwo!', False))
- fakemgr.add_user('acc2', User('guy2', 'guy2', 'acc2',
- 'swordfish', True))
+ fakemgr.add_user(User('guy1', 'guy1', 'acc1', 'fortytwo!', False))
+ fakemgr.add_user(User('guy2', 'guy2', 'acc2', 'swordfish', True))
def tearDown(self):
self.stubs.UnsetAll()
@@ -95,7 +93,7 @@ class UsersTest(test.TestCase):
req.method = 'DELETE'
res = req.get_response(fakes.wsgi_app())
self.assertTrue('guy1' not in [u.id for u in
- fakes.FakeAuthManager.auth_data.values()])
+ fakes.FakeAuthManager.auth_data])
self.assertEqual(res.status_int, 200)
def test_user_create(self):
@@ -118,8 +116,8 @@ class UsersTest(test.TestCase):
self.assertEqual(res_dict['user']['secret'], 'invasionIsInNormandy')
self.assertEqual(res_dict['user']['admin'], True)
self.assertTrue('test_guy' in [u.id for u in
- fakes.FakeAuthManager.auth_data.values()])
- self.assertEqual(len(fakes.FakeAuthManager.auth_data.values()), 3)
+ fakes.FakeAuthManager.auth_data])
+ self.assertEqual(len(fakes.FakeAuthManager.auth_data), 3)
def test_user_update(self):
body = dict(user=dict(name='guy2',
--
cgit
From bacce305a99dff77aa0e24c64cb937514e368ec1 Mon Sep 17 00:00:00 2001
From: Anne Gentle
Date: Fri, 11 Mar 2011 17:13:56 -0600
Subject: Adding a sidebar element to the nova.openstack.org site to point
people to additional versions of the site.
---
doc/source/_static/tweaks.css | 147 ++++++++++++++++++++++++++++++++++++++++++
doc/source/_theme/layout.html | 11 +++-
2 files changed, 157 insertions(+), 1 deletion(-)
diff --git a/doc/source/_static/tweaks.css b/doc/source/_static/tweaks.css
index 1a18dbac6..7c57c8f35 100644
--- a/doc/source/_static/tweaks.css
+++ b/doc/source/_static/tweaks.css
@@ -69,3 +69,150 @@ table.docutils {
.tweet_list li .tweet_avatar {
float: left;
}
+
+/* ------------------------------------------
+PURE CSS SPEECH BUBBLES
+by Nicolas Gallagher
+- http://nicolasgallagher.com/pure-css-speech-bubbles/
+
+http://nicolasgallagher.com
+http://twitter.com/necolas
+
+Created: 02 March 2010
+Version: 1.1 (21 October 2010)
+
+Dual licensed under MIT and GNU GPLv2 © Nicolas Gallagher
+------------------------------------------ */
+/* THE SPEECH BUBBLE
+------------------------------------------------------------------------------------------------------------------------------- */
+
+/* THE SPEECH BUBBLE
+------------------------------------------------------------------------------------------------------------------------------- */
+
+.triangle-border {
+ position:relative;
+ padding:15px;
+ margin:1em 0 3em;
+ border:5px solid #BC1518;
+ color:#333;
+ background:#fff;
+
+ /* css3 */
+ -moz-border-radius:10px;
+ -webkit-border-radius:10px;
+ border-radius:10px;
+}
+
+/* Variant : for left positioned triangle
+------------------------------------------ */
+
+.triangle-border.left {
+ margin-left:30px;
+}
+
+/* Variant : for right positioned triangle
+------------------------------------------ */
+
+.triangle-border.right {
+ margin-right:30px;
+}
+
+/* THE TRIANGLE
+------------------------------------------------------------------------------------------------------------------------------- */
+
+.triangle-border:before {
+ content:"";
+ display:block; /* reduce the damage in FF3.0 */
+ position:absolute;
+ bottom:-40px; /* value = - border-top-width - border-bottom-width */
+ left:40px; /* controls horizontal position */
+ width:0;
+ height:0;
+ border:20px solid transparent;
+ border-top-color:#BC1518;
+}
+
+/* creates the smaller triangle */
+.triangle-border:after {
+ content:"";
+ display:block; /* reduce the damage in FF3.0 */
+ position:absolute;
+ bottom:-26px; /* value = - border-top-width - border-bottom-width */
+ left:47px; /* value = (:before left) + (:before border-left) - (:after border-left) */
+ width:0;
+ height:0;
+ border:13px solid transparent;
+ border-top-color:#fff;
+}
+
+/* Variant : top
+------------------------------------------ */
+
+/* creates the larger triangle */
+.triangle-border.top:before {
+ top:-40px; /* value = - border-top-width - border-bottom-width */
+ right:40px; /* controls horizontal position */
+ bottom:auto;
+ left:auto;
+ border:20px solid transparent;
+ border-bottom-color:#BC1518;
+}
+
+/* creates the smaller triangle */
+.triangle-border.top:after {
+ top:-26px; /* value = - border-top-width - border-bottom-width */
+ right:47px; /* value = (:before right) + (:before border-right) - (:after border-right) */
+ bottom:auto;
+ left:auto;
+ border:13px solid transparent;
+ border-bottom-color:#fff;
+}
+
+/* Variant : left
+------------------------------------------ */
+
+/* creates the larger triangle */
+.triangle-border.left:before {
+ top:10px; /* controls vertical position */
+ left:-30px; /* value = - border-left-width - border-right-width */
+ bottom:auto;
+ border-width:15px 30px 15px 0;
+ border-style:solid;
+ border-color:transparent #BC1518;
+}
+
+/* creates the smaller triangle */
+.triangle-border.left:after {
+ top:16px; /* value = (:before top) + (:before border-top) - (:after border-top) */
+ left:-21px; /* value = - border-left-width - border-right-width */
+ bottom:auto;
+ border-width:9px 21px 9px 0;
+ border-style:solid;
+ border-color:transparent #fff;
+}
+
+/* Variant : right
+------------------------------------------ */
+
+/* creates the larger triangle */
+.triangle-border.right:before {
+ top:10px; /* controls vertical position */
+ right:-30px; /* value = - border-left-width - border-right-width */
+ bottom:auto;
+ left:auto;
+ border-width:15px 0 15px 30px;
+ border-style:solid;
+ border-color:transparent #BC1518;
+}
+
+/* creates the smaller triangle */
+.triangle-border.right:after {
+ top:16px; /* value = (:before top) + (:before border-top) - (:after border-top) */
+ right:-21px; /* value = - border-left-width - border-right-width */
+ bottom:auto;
+ left:auto;
+ border-width:9px 0 9px 21px;
+ border-style:solid;
+ border-color:transparent #fff;
+}
+
diff --git a/doc/source/_theme/layout.html b/doc/source/_theme/layout.html
index e3eb54b71..958c512e4 100644
--- a/doc/source/_theme/layout.html
+++ b/doc/source/_theme/layout.html
@@ -71,12 +71,21 @@
+
+
+ Psst... hey. You're reading the latest content, but it might be out of sync with code. You can read Nova 2011.1 docs or all OpenStack docs too.
+
+
{%- endif %}
{%- if pagename == "index" %}
- {{ _('Twitter Feed') }}
+
+
+ {{ _('Twitter Feed') }}
{%- endif %}
+
+
{%- endblock %}
--
cgit
From d45947d83fa22f98b0889d269d447fabaa764a3c Mon Sep 17 00:00:00 2001
From: Anne Gentle
Date: Mon, 14 Mar 2011 09:48:58 -0500
Subject: Fixes link to 2011.1 instad of just to trunk docs
---
doc/source/_theme/layout.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/source/_theme/layout.html b/doc/source/_theme/layout.html
index 958c512e4..0a37a7943 100644
--- a/doc/source/_theme/layout.html
+++ b/doc/source/_theme/layout.html
@@ -73,7 +73,7 @@
- Psst... hey. You're reading the latest content, but it might be out of sync with code. You can read Nova 2011.1 docs or all OpenStack docs too.
+ Psst... hey. You're reading the latest content, but it might be out of sync with code. You can read Nova 2011.1 docs or all OpenStack docs too.
{%- endif %}
--
cgit
From 06051ac8660983aae9ea6e72ab9bb1a31ceed9af Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Mon, 14 Mar 2011 11:08:00 -0700
Subject: Reverted unmodified files
---
tools/ajaxterm/README.txt | 240 +++++++++++++++++++++++-----------------------
1 file changed, 120 insertions(+), 120 deletions(-)
diff --git a/tools/ajaxterm/README.txt b/tools/ajaxterm/README.txt
index a649771c5..4b0ae99af 100644
--- a/tools/ajaxterm/README.txt
+++ b/tools/ajaxterm/README.txt
@@ -1,120 +1,120 @@
-= [http://antony.lesuisse.org/qweb/trac/wiki/AjaxTerm Ajaxterm] =
-
-Ajaxterm is a web based terminal. It was totally inspired and works almost
-exactly like http://anyterm.org/ except it's much easier to install (see
-comparaison with anyterm below).
-
-Ajaxterm written in python (and some AJAX javascript for client side) and depends only on python2.3 or better.[[BR]]
-Ajaxterm is '''very simple to install''' on Linux, MacOS X, FreeBSD, Solaris, cygwin and any Unix that runs python2.3.[[BR]]
-Ajaxterm was written by Antony Lesuisse (email: al AT udev.org), License Public Domain.
-
-Use the [/qweb/forum/viewforum.php?id=2 Forum], if you have any question or remark.
-
-== News ==
-
- * 2006-10-29: v0.10 allow space in login, cgi launch fix, redhat init
- * 2006-07-12: v0.9 change uid, daemon fix (Daniel Fischer)
- * 2006-07-04: v0.8 add login support to ssh (Sven Geggus), change max width to 256
- * 2006-05-31: v0.7 minor fixes, daemon option
- * 2006-05-23: v0.6 Applied debian and gentoo patches, renamed to Ajaxterm, default port 8022
-
-== Download and Install ==
-
- * Release: [/qweb/files/Ajaxterm-0.10.tar.gz Ajaxterm-0.10.tar.gz]
- * Browse src: [/qweb/trac/browser/trunk/ajaxterm/ ajaxterm/]
-
-To install Ajaxterm issue the following commands:
-{{{
-wget http://antony.lesuisse.org/qweb/files/Ajaxterm-0.10.tar.gz
-tar zxvf Ajaxterm-0.10.tar.gz
-cd Ajaxterm-0.10
-./ajaxterm.py
-}}}
-Then point your browser to this URL : http://localhost:8022/
-
-== Screenshot ==
-
-{{{
-#!html
-
-}}}
-
-== Documentation and Caveats ==
-
- * Ajaxterm only support latin1, if you use Ubuntu or any LANG==en_US.UTF-8 distribution don't forget to "unset LANG".
-
- * If run as root ajaxterm will run /bin/login, otherwise it will run ssh
- localhost. To use an other command use the -c option.
-
- * By default Ajaxterm only listen at 127.0.0.1:8022. For remote access, it is
- strongly recommended to use '''https SSL/TLS''', and that is simple to
- configure if you use the apache web server using mod_proxy.[[BR]][[BR]]
- Using ssl will also speed up ajaxterm (probably because of keepalive).[[BR]][[BR]]
- Here is an configuration example:
-
-{{{
- Listen 443
- NameVirtualHost *:443
-
-
- ServerName localhost
- SSLEngine On
- SSLCertificateKeyFile ssl/apache.pem
- SSLCertificateFile ssl/apache.pem
-
- ProxyRequests Off
-
- Order deny,allow
- Allow from all
-
- ProxyPass /ajaxterm/ http://localhost:8022/
- ProxyPassReverse /ajaxterm/ http://localhost:8022/
-
-}}}
-
- * Using GET HTTP request seems to speed up ajaxterm, just click on GET in the
- interface, but be warned that your keystrokes might be loggued (by apache or
- any proxy). I usually enable it after the login.
-
- * Ajaxterm commandline usage:
-
-{{{
-usage: ajaxterm.py [options]
-
-options:
- -h, --help show this help message and exit
- -pPORT, --port=PORT Set the TCP port (default: 8022)
- -cCMD, --command=CMD set the command (default: /bin/login or ssh localhost)
- -l, --log log requests to stderr (default: quiet mode)
- -d, --daemon run as daemon in the background
- -PPIDFILE, --pidfile=PIDFILE
- set the pidfile (default: /var/run/ajaxterm.pid)
- -iINDEX_FILE, --index=INDEX_FILE
- default index file (default: ajaxterm.html)
- -uUID, --uid=UID Set the daemon's user id
-}}}
-
- * Ajaxterm was first written as a demo for qweb (my web framework), but
- actually doesn't use many features of qweb.
-
- * Compared to anyterm:
- * There are no partial updates, ajaxterm updates either all the screen or
- nothing. That make the code simpler and I also think it's faster. HTTP
- replies are always gzencoded. When used in 80x25 mode, almost all of
- them are below the 1500 bytes (size of an ethernet frame) and we just
- replace the screen with the reply (no javascript string handling).
- * Ajaxterm polls the server for updates with an exponentially growing
- timeout when the screen hasn't changed. The timeout is also resetted as
- soon as a key is pressed. Anyterm blocks on a pending request and use a
- parallel connection for keypresses. The anyterm approch is better
- when there aren't any keypress.
-
- * Ajaxterm files are released in the Public Domain, (except [http://sarissa.sourceforge.net/doc/ sarissa*] which are LGPL).
-
-== TODO ==
-
- * insert mode ESC [ 4 h
- * change size x,y from gui (sending signal)
- * vt102 graphic codepage
- * use innerHTML or prototype instead of sarissa
-
+= [http://antony.lesuisse.org/qweb/trac/wiki/AjaxTerm Ajaxterm] =
+
+Ajaxterm is a web based terminal. It was totally inspired and works almost
+exactly like http://anyterm.org/ except it's much easier to install (see
+comparaison with anyterm below).
+
+Ajaxterm written in python (and some AJAX javascript for client side) and depends only on python2.3 or better.[[BR]]
+Ajaxterm is '''very simple to install''' on Linux, MacOS X, FreeBSD, Solaris, cygwin and any Unix that runs python2.3.[[BR]]
+Ajaxterm was written by Antony Lesuisse (email: al AT udev.org), License Public Domain.
+
+Use the [/qweb/forum/viewforum.php?id=2 Forum], if you have any question or remark.
+
+== News ==
+
+ * 2006-10-29: v0.10 allow space in login, cgi launch fix, redhat init
+ * 2006-07-12: v0.9 change uid, daemon fix (Daniel Fischer)
+ * 2006-07-04: v0.8 add login support to ssh (Sven Geggus), change max width to 256
+ * 2006-05-31: v0.7 minor fixes, daemon option
+ * 2006-05-23: v0.6 Applied debian and gentoo patches, renamed to Ajaxterm, default port 8022
+
+== Download and Install ==
+
+ * Release: [/qweb/files/Ajaxterm-0.10.tar.gz Ajaxterm-0.10.tar.gz]
+ * Browse src: [/qweb/trac/browser/trunk/ajaxterm/ ajaxterm/]
+
+To install Ajaxterm issue the following commands:
+{{{
+wget http://antony.lesuisse.org/qweb/files/Ajaxterm-0.10.tar.gz
+tar zxvf Ajaxterm-0.10.tar.gz
+cd Ajaxterm-0.10
+./ajaxterm.py
+}}}
+Then point your browser to this URL : http://localhost:8022/
+
+== Screenshot ==
+
+{{{
+#!html
+
+}}}
+
+== Documentation and Caveats ==
+
+ * Ajaxterm only support latin1, if you use Ubuntu or any LANG==en_US.UTF-8 distribution don't forget to "unset LANG".
+
+ * If run as root ajaxterm will run /bin/login, otherwise it will run ssh
+ localhost. To use an other command use the -c option.
+
+ * By default Ajaxterm only listen at 127.0.0.1:8022. For remote access, it is
+ strongly recommended to use '''https SSL/TLS''', and that is simple to
+ configure if you use the apache web server using mod_proxy.[[BR]][[BR]]
+ Using ssl will also speed up ajaxterm (probably because of keepalive).[[BR]][[BR]]
+ Here is an configuration example:
+
+{{{
+ Listen 443
+ NameVirtualHost *:443
+
+
+ ServerName localhost
+ SSLEngine On
+ SSLCertificateKeyFile ssl/apache.pem
+ SSLCertificateFile ssl/apache.pem
+
+ ProxyRequests Off
+
+ Order deny,allow
+ Allow from all
+
+ ProxyPass /ajaxterm/ http://localhost:8022/
+ ProxyPassReverse /ajaxterm/ http://localhost:8022/
+
+}}}
+
+ * Using GET HTTP request seems to speed up ajaxterm, just click on GET in the
+ interface, but be warned that your keystrokes might be loggued (by apache or
+ any proxy). I usually enable it after the login.
+
+ * Ajaxterm commandline usage:
+
+{{{
+usage: ajaxterm.py [options]
+
+options:
+ -h, --help show this help message and exit
+ -pPORT, --port=PORT Set the TCP port (default: 8022)
+ -cCMD, --command=CMD set the command (default: /bin/login or ssh localhost)
+ -l, --log log requests to stderr (default: quiet mode)
+ -d, --daemon run as daemon in the background
+ -PPIDFILE, --pidfile=PIDFILE
+ set the pidfile (default: /var/run/ajaxterm.pid)
+ -iINDEX_FILE, --index=INDEX_FILE
+ default index file (default: ajaxterm.html)
+ -uUID, --uid=UID Set the daemon's user id
+}}}
+
+ * Ajaxterm was first written as a demo for qweb (my web framework), but
+ actually doesn't use many features of qweb.
+
+ * Compared to anyterm:
+ * There are no partial updates, ajaxterm updates either all the screen or
+ nothing. That make the code simpler and I also think it's faster. HTTP
+ replies are always gzencoded. When used in 80x25 mode, almost all of
+ them are below the 1500 bytes (size of an ethernet frame) and we just
+ replace the screen with the reply (no javascript string handling).
+ * Ajaxterm polls the server for updates with an exponentially growing
+ timeout when the screen hasn't changed. The timeout is also resetted as
+ soon as a key is pressed. Anyterm blocks on a pending request and use a
+ parallel connection for keypresses. The anyterm approch is better
+ when there aren't any keypress.
+
+ * Ajaxterm files are released in the Public Domain, (except [http://sarissa.sourceforge.net/doc/ sarissa*] which are LGPL).
+
+== TODO ==
+
+ * insert mode ESC [ 4 h
+ * change size x,y from gui (sending signal)
+ * vt102 graphic codepage
+ * use innerHTML or prototype instead of sarissa
+
--
cgit
--
cgit
--
cgit
From 5a0d4fbc24e897e4aa861819fd2f861e7dedcb6b Mon Sep 17 00:00:00 2001
From: Trey Morris
Date: Mon, 14 Mar 2011 16:33:01 -0500
Subject: added structure to virt.xenapi.vmops to support network info being
passed in
---
nova/virt/xenapi/vmops.py | 109 ++++++++++++++++++++++++++--------------------
1 file changed, 62 insertions(+), 47 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index fcb290d03..bec403543 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -80,11 +80,11 @@ class VMOps(object):
instance.image_id, user, project, disk_image_type)
return vdi_uuid
- def spawn(self, instance):
+ def spawn(self, instance, network_info=None):
vdi_uuid = self.create_disk(instance)
- self._spawn_with_disk(instance, vdi_uuid=vdi_uuid)
+ self._spawn_with_disk(instance, vdi_uuid=vdi_uuid, network_info)
- def _spawn_with_disk(self, instance, vdi_uuid):
+ def _spawn_with_disk(self, instance, vdi_uuid, network_info=None):
"""Create VM instance"""
instance_name = instance.name
vm_ref = VMHelper.lookup(self._session, instance_name)
@@ -128,8 +128,13 @@ class VMOps(object):
vdi_ref=vdi_ref, userdevice=0, bootable=True)
# inject_network_info and create vifs
- networks = self.inject_network_info(instance)
- self.create_vifs(instance, networks)
+ if network_info is not None:
+ self.inject_network_info(instance, network_info)
+ self.create_vifs(instance, [nw for (nw, mapping) in network_info])
+ else:
+ # TODO(tr3buchet) - goes away with multi-nic
+ networks = self.inject_network_info(instance)
+ self.create_vifs(instance, networks)
LOG.debug(_('Starting VM %s...'), vm_ref)
self._start(instance, vm_ref)
@@ -684,59 +689,68 @@ class VMOps(object):
# TODO: implement this!
return 'http://fakeajaxconsole/fake_url'
- def inject_network_info(self, instance):
+ def inject_network_info(self, instance, network_info=None):
"""
Generate the network info and make calls to place it into the
xenstore and the xenstore param list
"""
- # TODO(tr3buchet) - remove comment in multi-nic
- # I've decided to go ahead and consider multiple IPs and networks
- # at this stage even though they aren't implemented because these will
- # be needed for multi-nic and there was no sense writing it for single
- # network/single IP and then having to turn around and re-write it
vm_ref = self._get_vm_opaque_ref(instance.id)
logging.debug(_("injecting network info to xenstore for vm: |%s|"),
vm_ref)
- admin_context = context.get_admin_context()
- IPs = db.fixed_ip_get_all_by_instance(admin_context, instance['id'])
- networks = db.network_get_all_by_instance(admin_context,
+ if network_info is not None:
+ for (network, mapping) in network_info:
+ self.write_to_param_xenstore(vm_ref, {location: mapping})
+ try:
+ self.write_to_xenstore(vm_ref, location,
+ mapping['location'])
+ except KeyError:
+ # catch KeyError for domid if instance isn't running
+ pass
+ else:
+ # TODO(tr3buchet) - this bit here when network_info is None goes
+ # away with multi-nic
+ admin_context = context.get_admin_context()
+ IPs = db.fixed_ip_get_all_by_instance(admin_context,
instance['id'])
- for network in networks:
- network_IPs = [ip for ip in IPs if ip.network_id == network.id]
-
- def ip_dict(ip):
- return {
- "ip": ip.address,
- "netmask": network["netmask"],
- "enabled": "1"}
-
- def ip6_dict(ip6):
- return {
- "ip": ip6.addressV6,
- "netmask": ip6.netmaskV6,
- "gateway": ip6.gatewayV6,
- "enabled": "1"}
-
- mac_id = instance.mac_address.replace(':', '')
- location = 'vm-data/networking/%s' % mac_id
- mapping = {
- 'label': network['label'],
- 'gateway': network['gateway'],
- 'mac': instance.mac_address,
- 'dns': [network['dns']],
- 'ips': [ip_dict(ip) for ip in network_IPs],
- 'ip6s': [ip6_dict(ip) for ip in network_IPs]}
-
- self.write_to_param_xenstore(vm_ref, {location: mapping})
+ networks = db.network_get_all_by_instance(admin_context,
+ instance['id'])
+ for network in networks:
+ network_IPs = [ip for ip in IPs if ip.network_id == network.id]
+
+ def ip_dict(ip):
+ return {
+ "ip": ip.address,
+ "netmask": network["netmask"],
+ "enabled": "1"}
+
+ def ip6_dict(ip6):
+ return {
+ "ip": ip6.addressV6,
+ "netmask": ip6.netmaskV6,
+ "gateway": ip6.gatewayV6,
+ "enabled": "1"}
+
+ mac_id = instance.mac_address.replace(':', '')
+ location = 'vm-data/networking/%s' % mac_id
+ mapping = {
+ 'label': network['label'],
+ 'gateway': network['gateway'],
+ 'mac': instance.mac_address,
+ 'dns': [network['dns']],
+ 'ips': [ip_dict(ip) for ip in network_IPs],
+ 'ip6s': [ip6_dict(ip) for ip in network_IPs]}
+
+ self.write_to_param_xenstore(vm_ref, {location: mapping})
- try:
- self.write_to_xenstore(vm_ref, location, mapping['location'])
- except KeyError:
- # catch KeyError for domid if instance isn't running
- pass
+ try:
+ self.write_to_xenstore(vm_ref, location,
+ mapping['location'])
+ except KeyError:
+ # catch KeyError for domid if instance isn't running
+ pass
- return networks
+ return networks
def create_vifs(self, instance, networks=None):
"""
@@ -745,6 +759,7 @@ class VMOps(object):
"""
vm_ref = self._get_vm_opaque_ref(instance.id)
logging.debug(_("creating vif(s) for vm: |%s|"), vm_ref)
+ # TODO(tr3buchet) - goes away with multi-nic
if networks is None:
networks = db.network_get_all_by_instance(admin_context,
instance['id'])
--
cgit
From 1d1e5e38175ff7956b3a28ccc1ce61f700700e8b Mon Sep 17 00:00:00 2001
From: Trey Morris
Date: Mon, 14 Mar 2011 16:38:53 -0500
Subject: fixed keyword arg error
---
nova/virt/xenapi/vmops.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index bec403543..64f2c6231 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -82,7 +82,7 @@ class VMOps(object):
def spawn(self, instance, network_info=None):
vdi_uuid = self.create_disk(instance)
- self._spawn_with_disk(instance, vdi_uuid=vdi_uuid, network_info)
+ self._spawn_with_disk(instance, vdi_uuid, network_info)
def _spawn_with_disk(self, instance, vdi_uuid, network_info=None):
"""Create VM instance"""
--
cgit
From 5b1422afe12d4e9b7fdfdc6a61cdcd51962dab4d Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Mon, 14 Mar 2011 14:43:53 -0700
Subject: Fix for LP Bug #704300
---
nova/virt/libvirt_conn.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index 0b306c950..e0222956e 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -339,7 +339,11 @@ class LibvirtConnection(object):
def reboot(self, instance):
self.destroy(instance, False)
xml = self.to_xml(instance)
+ self.firewall_driver.setup_basic_filtering(instance)
+ self.firewall_driver.prepare_instance_filter(instance)
self._conn.createXML(xml, 0)
+ self.firewall_driver.apply_instance_filter(instance)
+
timer = utils.LoopingCall(f=None)
def _wait_for_reboot():
--
cgit
From 2b20306fcaddcb6b9bc57fb55b17230d709cd1ce Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Mon, 14 Mar 2011 22:23:38 -0700
Subject: Derive unit test from standard nova.test.TestCase
---
nova/tests/integrated/test_login.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/nova/tests/integrated/test_login.py b/nova/tests/integrated/test_login.py
index e362f92d6..5fa558bdf 100644
--- a/nova/tests/integrated/test_login.py
+++ b/nova/tests/integrated/test_login.py
@@ -18,6 +18,7 @@
import unittest
from nova import flags
+from nova import test
from nova.log import logging
from nova.tests.integrated import integrated_helpers
from nova.tests.integrated.api import client
@@ -29,7 +30,7 @@ FLAGS = flags.FLAGS
FLAGS.verbose = True
-class LoginTest(unittest.TestCase):
+class LoginTest(test.TestCase):
def setUp(self):
super(LoginTest, self).setUp()
context = integrated_helpers.IntegratedUnitTestContext.startup()
@@ -73,5 +74,6 @@ class LoginTest(unittest.TestCase):
self.assertRaises(client.OpenstackApiAuthenticationException,
bad_credentials_api.get_flavors)
+
if __name__ == "__main__":
unittest.main()
--
cgit
From db8beffc9acd90c748512c1fa9c127d39756232c Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Mon, 14 Mar 2011 22:36:30 -0700
Subject: Reapplied rename of Openstack -> OpenStack. Easier to do it by hand
than to ask Bazaar to do it.
---
nova/tests/integrated/api/client.py | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/nova/tests/integrated/api/client.py b/nova/tests/integrated/api/client.py
index 6fba2930a..568e8c17e 100644
--- a/nova/tests/integrated/api/client.py
+++ b/nova/tests/integrated/api/client.py
@@ -24,7 +24,7 @@ from nova import log as logging
LOG = logging.getLogger('nova.tests.api')
-class OpenstackApiException(Exception):
+class OpenStackApiException(Exception):
def __init__(self, message=None, response=None):
self.response = response
if not message:
@@ -37,22 +37,22 @@ class OpenstackApiException(Exception):
message = _('%(message)s\nStatus Code: %(_status)s\n'
'Body: %(_body)s') % locals()
- super(OpenstackApiException, self).__init__(message)
+ super(OpenStackApiException, self).__init__(message)
-class OpenstackApiAuthenticationException(OpenstackApiException):
+class OpenStackApiAuthenticationException(OpenStackApiException):
def __init__(self, response=None, message=None):
if not message:
message = _("Authentication error")
- super(OpenstackApiAuthenticationException, self).__init__(message,
+ super(OpenStackApiAuthenticationException, self).__init__(message,
response)
-class OpenstackApiNotFoundException(OpenstackApiException):
+class OpenStackApiNotFoundException(OpenStackApiException):
def __init__(self, response=None, message=None):
if not message:
message = _("Item not found")
- super(OpenstackApiNotFoundException, self).__init__(message, response)
+ super(OpenStackApiNotFoundException, self).__init__(message, response)
class TestOpenStackClient(object):
@@ -82,7 +82,7 @@ class TestOpenStackClient(object):
conn = httplib.HTTPSConnection(hostname,
port=port)
else:
- raise OpenstackApiException("Unknown scheme: %s" % url)
+ raise OpenStackApiException("Unknown scheme: %s" % url)
relative_url = parsed_url.path
if parsed_url.query:
@@ -112,7 +112,7 @@ class TestOpenStackClient(object):
# bug732866
#if http_status == 401:
if http_status != 204:
- raise OpenstackApiAuthenticationException(response=response)
+ raise OpenStackApiAuthenticationException(response=response)
auth_headers = {}
for k, v in response.getheaders():
@@ -139,9 +139,9 @@ class TestOpenStackClient(object):
if check_response_status:
if not http_status in check_response_status:
if http_status == 404:
- raise OpenstackApiNotFoundException(response=response)
+ raise OpenStackApiNotFoundException(response=response)
else:
- raise OpenstackApiException(
+ raise OpenStackApiException(
message=_("Unexpected status code"),
response=response)
--
cgit
From e0563f49792441af106c52e662bdada3c7997feb Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Mon, 14 Mar 2011 22:43:21 -0700
Subject: Reapplied rename to another file.
---
nova/tests/integrated/test_login.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/nova/tests/integrated/test_login.py b/nova/tests/integrated/test_login.py
index 5fa558bdf..501f8c919 100644
--- a/nova/tests/integrated/test_login.py
+++ b/nova/tests/integrated/test_login.py
@@ -53,7 +53,7 @@ class LoginTest(test.TestCase):
"notso_password",
self.user.auth_url)
- self.assertRaises(client.OpenstackApiAuthenticationException,
+ self.assertRaises(client.OpenStackApiAuthenticationException,
bad_credentials_api.get_flavors)
def test_bad_login_username(self):
@@ -62,7 +62,7 @@ class LoginTest(test.TestCase):
self.user.secret,
self.user.auth_url)
- self.assertRaises(client.OpenstackApiAuthenticationException,
+ self.assertRaises(client.OpenStackApiAuthenticationException,
bad_credentials_api.get_flavors)
def test_bad_login_both_bad(self):
@@ -71,7 +71,7 @@ class LoginTest(test.TestCase):
"notso_password",
self.user.auth_url)
- self.assertRaises(client.OpenstackApiAuthenticationException,
+ self.assertRaises(client.OpenStackApiAuthenticationException,
bad_credentials_api.get_flavors)
--
cgit
From 4b49df7e7232dfd3e187faac52b9eb72773be360 Mon Sep 17 00:00:00 2001
From: Brian Lamar
Date: Tue, 15 Mar 2011 16:49:19 -0400
Subject: Major cosmetic changes to limits, but little-to-no functional
changes. MUCH better testability now, no more relying on system time to tick
by for limit testing.
---
etc/api-paste.ini | 2 +-
nova/api/openstack/__init__.py | 6 +
nova/api/openstack/faults.py | 21 ++
nova/api/openstack/limits.py | 342 ++++++++++++++++++++
nova/tests/api/openstack/__init__.py | 2 +-
nova/tests/api/openstack/fakes.py | 10 +-
nova/tests/api/openstack/test_adminapi.py | 1 -
nova/tests/api/openstack/test_ratelimiting.py | 443 +++++++++++++++++---------
8 files changed, 669 insertions(+), 158 deletions(-)
create mode 100644 nova/api/openstack/limits.py
diff --git a/etc/api-paste.ini b/etc/api-paste.ini
index 9f7e93d4c..750f0ad87 100644
--- a/etc/api-paste.ini
+++ b/etc/api-paste.ini
@@ -79,7 +79,7 @@ paste.filter_factory = nova.api.openstack:FaultWrapper.factory
paste.filter_factory = nova.api.openstack.auth:AuthMiddleware.factory
[filter:ratelimit]
-paste.filter_factory = nova.api.openstack.ratelimiting:RateLimitingMiddleware.factory
+paste.filter_factory = nova.api.openstack.limits:RateLimitingMiddleware.factory
[app:osapiapp]
paste.app_factory = nova.api.openstack:APIRouter.factory
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py
index ce3cff337..db2dff8d5 100644
--- a/nova/api/openstack/__init__.py
+++ b/nova/api/openstack/__init__.py
@@ -33,6 +33,7 @@ from nova.api.openstack import backup_schedules
from nova.api.openstack import consoles
from nova.api.openstack import flavors
from nova.api.openstack import images
+from nova.api.openstack import limits
from nova.api.openstack import servers
from nova.api.openstack import shared_ip_groups
from nova.api.openstack import users
@@ -114,12 +115,17 @@ class APIRouter(wsgi.Router):
mapper.resource("image", "images", controller=images.Controller(),
collection={'detail': 'GET'})
+
mapper.resource("flavor", "flavors", controller=flavors.Controller(),
collection={'detail': 'GET'})
+
mapper.resource("shared_ip_group", "shared_ip_groups",
collection={'detail': 'GET'},
controller=shared_ip_groups.Controller())
+ _limits = limits.LimitsController()
+ mapper.resource("limit", "limits", controller=_limits)
+
super(APIRouter, self).__init__(mapper)
diff --git a/nova/api/openstack/faults.py b/nova/api/openstack/faults.py
index 2fd733299..6ed9322de 100644
--- a/nova/api/openstack/faults.py
+++ b/nova/api/openstack/faults.py
@@ -61,3 +61,24 @@ class Fault(webob.exc.HTTPException):
content_type = req.best_match_content_type()
self.wrapped_exc.body = serializer.serialize(fault_data, content_type)
return self.wrapped_exc
+
+
+class OverLimitFault(webob.exc.HTTPException):
+ """
+ Rate-limited request response.
+ """
+
+ wrapped_exc = webob.exc.HTTPForbidden()
+
+ def __init__(self, message, details, retry_time):
+ """
+ Initialize new `OverLimitFault` with relevant information.
+ """
+ self.message = message
+ self.details = details
+ self.retry_time = retry_time
+
+ @webob.dec.wsgify(RequestClass=wsgi.Request)
+ def __call__(self, request):
+ """Currently just return the wrapped exception."""
+ return self.wrapped_exc
diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py
new file mode 100644
index 000000000..4f64cab3c
--- /dev/null
+++ b/nova/api/openstack/limits.py
@@ -0,0 +1,342 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 OpenStack LLC.
+# All Rights Reserved.
+#
+# 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 datetime
+
+"""
+Module dedicated functions/classes dealing with rate limiting requests.
+"""
+
+import copy
+import httplib
+import json
+import math
+import re
+import time
+import urllib
+import webob.exc
+
+from collections import defaultdict
+
+from webob.dec import wsgify
+
+from nova import wsgi
+from nova.api.openstack import faults
+from nova.wsgi import Controller
+from nova.wsgi import Middleware
+
+
+# Convenience constants for the limits dictionary passed to Limiter().
+PER_SECOND = 1
+PER_MINUTE = 60
+PER_HOUR = 60 * 60
+PER_DAY = 60 * 60 * 24
+
+
+class LimitsController(Controller):
+ """
+ Controller for accessing limits in the OpenStack API.
+ """
+
+ def index(self, req):
+ """
+ Return all global and rate limit information.
+ """
+ abs_limits = {}
+ rate_limits = req.environ.get("nova.limits", {})
+
+ return {
+ "limits" : {
+ "rate" : rate_limits,
+ "absolute" : abs_limits,
+ },
+ }
+
+
+class Limit(object):
+ """
+ Stores information about a limit for HTTP requets.
+ """
+
+ UNITS = {
+ 1 : "SECOND",
+ 60 : "MINUTE",
+ 60 * 60 : "HOUR",
+ 60 * 60 * 24 : "DAY",
+ }
+
+ def __init__(self, verb, uri, regex, value, unit):
+ """
+ Initialize a new `Limit`.
+
+ @param verb: HTTP verb (POST, PUT, etc.)
+ @param uri: Human-readable URI
+ @param regex: Regular expression format for this limit
+ @param value: Integer number of requests which can be made
+ @param unit: Unit of measure for the value parameter
+ """
+ self.verb = verb
+ self.uri = uri
+ self.regex = regex
+ self.value = int(value)
+ self.unit = unit
+ self.remaining = int(value)
+
+ if value <= 0:
+ raise ValueError("Limit value must be > 0")
+
+ self.last_request = None
+ self.next_request = None
+
+ self.water_level = 0
+ self.capacity = float(self.unit)
+ self.request_value = float(self.capacity) / float(self.value)
+
+ def __call__(self, verb, url):
+ """
+ Represents a call to this limit from a relevant request.
+
+ @param verb: string http verb (POST, GET, etc.)
+ @param url: string URL
+ """
+ if self.verb != verb or not re.match(self.regex, url):
+ return
+
+ now = self._get_time()
+
+ if self.last_request is None:
+ self.last_request = now
+
+ leak_value = now - self.last_request
+
+ self.water_level -= leak_value
+ self.water_level = max(self.water_level, 0)
+ self.water_level += self.request_value
+
+ difference = self.water_level - self.capacity
+
+ self.last_request = now
+
+ if difference > 0:
+ self.water_level -= self.request_value
+ self.next_request = now + difference
+ return difference
+
+ cap = self.capacity
+ water = self.water_level
+ val = self.value
+
+ self.remaining = math.floor((cap - water) / cap * val)
+ print "Remaining:", self.remaining
+ self.next_request = now
+
+ def _get_time(self):
+ """Retrieve the current time. Broken out for testability."""
+ return time.time()
+
+ def display_unit(self):
+ """Display the string name of the unit."""
+ return self.UNITS.get(self.unit, "UNKNOWN")
+
+ def display(self):
+ """Return a useful representation of this class."""
+ return {
+ "verb" : self.verb,
+ "uri" : self.uri,
+ "regex" : self.regex,
+ "value" : self.value,
+ "remaining" : int(self.remaining),
+ "unit" : self.display_unit(),
+ "resetTime" : int(self.next_request or self._get_time()),
+ }
+
+
+
+# "Limit" format is a dictionary with the HTTP verb, human-readable URI,
+# a regular-expression to match, value and unit of measure (PER_DAY, etc.)
+
+DEFAULT_LIMITS = [
+ Limit("POST", "*", ".*", 10, PER_MINUTE),
+ Limit("POST", "*/servers", "^/servers", 50, PER_DAY),
+ Limit("PUT", "*", ".*", 10, PER_MINUTE),
+ Limit("GET", "*changes-since*", ".*changes-since.*", 3, PER_MINUTE),
+ Limit("DELETE", "*", ".*", 100, PER_MINUTE),
+]
+
+
+class RateLimitingMiddleware(Middleware):
+ """
+ Rate-limits requests passing through this middleware. All limit information
+ is stored in memory for this implementation.
+ """
+
+ def __init__(self, application, limits=None):
+ """
+ Initialize new `RateLimitingMiddleware`, which wraps the given WSGI
+ application and sets up the given limits.
+
+ @param application: WSGI application to wrap
+ @param limits: List of dictionaries describing limits
+ """
+ Middleware.__init__(self, application)
+ self._limiter = Limiter(limits or DEFAULT_LIMITS)
+
+ @wsgify(RequestClass=wsgi.Request)
+ def __call__(self, req):
+ """
+ Represents a single call through this middleware. We should record the
+ request if we have a limit relevant to it. If no limit is relevant to
+ the request, ignore it.
+
+ If the request should be rate limited, return a fault telling the user
+ they are over the limit and need to retry later.
+ """
+ verb = req.method
+ url = req.url
+ username = req.environ["nova.context"].user_id
+
+ delay = self._limiter.check_for_delay(verb, url, username)
+
+ if delay:
+ msg = "This request was rate-limited."
+ details = "Error details."
+ retry = time.time() + delay
+ return faults.OverLimitFault(msg, details, retry)
+
+ req.environ["nova.limits"] = self._limiter.get_limits(username)
+
+ return self.application
+
+
+class Limiter(object):
+ """
+ Rate-limit checking class which handles limits in memory.
+ """
+
+ def __init__(self, limits):
+ """
+ Initialize the new `Limiter`.
+
+ @param limits: List of `Limit` objects
+ """
+ self.limits = copy.deepcopy(limits)
+ self.levels = defaultdict(lambda: copy.deepcopy(limits))
+
+ def get_limits(self, username=None):
+ """
+ Return the limits for a given user.
+ """
+ return [limit.display() for limit in self.levels[username]]
+
+ def check_for_delay(self, verb, url, username=None):
+ """
+ Check the given verb/user/user triplet for limit.
+ """
+ def _get_delay_list():
+ """Yield limit delays."""
+ for limit in self.levels[username]:
+ delay = limit(verb, url)
+ if delay:
+ yield delay
+
+ delays = list(_get_delay_list())
+
+ if delays:
+ delays.sort()
+ return delays[0]
+
+
+class WsgiLimiter(object):
+ """
+ Rate-limit checking from a WSGI application. Uses an in-memory `Limiter`.
+
+ To use:
+ POST / with JSON data such as:
+ {
+ "verb" : GET,
+ "path" : "/servers"
+ }
+
+ and receive a 204 No Content, or a 403 Forbidden with an X-Wait-Seconds
+ header containing the number of seconds to wait before the action would
+ succeed.
+ """
+
+ def __init__(self, limits=None):
+ """
+ Initialize the new `WsgiLimiter`.
+
+ @param limits: List of `Limit` objects
+ """
+ self._limiter = Limiter(limits or DEFAULT_LIMITS)
+
+ @wsgify(RequestClass=wsgi.Request)
+ def __call__(self, request):
+ """
+ Handles a call to this application. Returns 204 if the request is
+ acceptable to the limiter, else a 403 is returned with a relevant
+ header indicating when the request *will* succeed.
+ """
+ if request.method != "POST":
+ raise webob.exc.HTTPMethodNotAllowed()
+
+ try:
+ info = dict(json.loads(request.body))
+ except ValueError:
+ raise webob.exc.HTTPBadRequest()
+
+ username = request.path_info_pop()
+ verb = info.get("verb")
+ path = info.get("path")
+
+ delay = self._limiter.check_for_delay(verb, path, username)
+
+ if delay:
+ headers = {"X-Wait-Seconds": "%.2f" % delay}
+ return webob.exc.HTTPForbidden(headers=headers)
+ else:
+ return webob.exc.HTTPNoContent()
+
+
+class WsgiLimiterProxy(object):
+ """
+ Rate-limit requests based on answers from a remote source.
+ """
+
+ def __init__(self, limiter_address):
+ """
+ Initialize the new `WsgiLimiterProxy`.
+
+ @param limiter_address: IP/port combination of where to request limit
+ """
+ self.limiter_address = limiter_address
+
+ def check_for_delay(self, verb, path, username=None):
+ body = json.dumps({"verb":verb,"path":path})
+ headers = {"Content-Type" : "application/json"}
+
+ conn = httplib.HTTPConnection(self.limiter_address)
+
+ if username:
+ conn.request("POST", "/%s" % (username), body, headers)
+ else:
+ conn.request("POST", "/", body, headers)
+
+ resp = conn.getresponse()
+
+ if 200 >= resp.status < 300:
+ return None
+
+ return resp.getheader("X-Wait-Seconds")
diff --git a/nova/tests/api/openstack/__init__.py b/nova/tests/api/openstack/__init__.py
index e18120285..bac7181f7 100644
--- a/nova/tests/api/openstack/__init__.py
+++ b/nova/tests/api/openstack/__init__.py
@@ -20,7 +20,7 @@ from nova import test
from nova import context
from nova import flags
-from nova.api.openstack.ratelimiting import RateLimitingMiddleware
+from nova.api.openstack.limits import RateLimitingMiddleware
from nova.api.openstack.common import limited
from nova.tests.api.openstack import fakes
from webob import Request
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py
index 7cb974bb2..ae95c0648 100644
--- a/nova/tests/api/openstack/fakes.py
+++ b/nova/tests/api/openstack/fakes.py
@@ -34,7 +34,7 @@ from nova import utils
import nova.api.openstack.auth
from nova.api import openstack
from nova.api.openstack import auth
-from nova.api.openstack import ratelimiting
+from nova.api.openstack import limits
from nova.auth.manager import User, Project
from nova.image import glance
from nova.image import local
@@ -79,7 +79,7 @@ def wsgi_app(inner_application=None):
inner_application = openstack.APIRouter()
mapper = urlmap.URLMap()
api = openstack.FaultWrapper(auth.AuthMiddleware(
- ratelimiting.RateLimitingMiddleware(inner_application)))
+ limits.RateLimitingMiddleware(inner_application)))
mapper['/v1.0'] = api
mapper['/'] = openstack.FaultWrapper(openstack.Versions())
return mapper
@@ -110,13 +110,13 @@ def stub_out_auth(stubs):
def stub_out_rate_limiting(stubs):
def fake_rate_init(self, app):
- super(ratelimiting.RateLimitingMiddleware, self).__init__(app)
+ super(limits.RateLimitingMiddleware, self).__init__(app)
self.application = app
- stubs.Set(nova.api.openstack.ratelimiting.RateLimitingMiddleware,
+ stubs.Set(nova.api.openstack.limits.RateLimitingMiddleware,
'__init__', fake_rate_init)
- stubs.Set(nova.api.openstack.ratelimiting.RateLimitingMiddleware,
+ stubs.Set(nova.api.openstack.limits.RateLimitingMiddleware,
'__call__', fake_wsgi)
diff --git a/nova/tests/api/openstack/test_adminapi.py b/nova/tests/api/openstack/test_adminapi.py
index 4568cb9f5..e87255b18 100644
--- a/nova/tests/api/openstack/test_adminapi.py
+++ b/nova/tests/api/openstack/test_adminapi.py
@@ -23,7 +23,6 @@ from paste import urlmap
from nova import flags
from nova import test
from nova.api import openstack
-from nova.api.openstack import ratelimiting
from nova.api.openstack import auth
from nova.tests.api.openstack import fakes
diff --git a/nova/tests/api/openstack/test_ratelimiting.py b/nova/tests/api/openstack/test_ratelimiting.py
index 9ae90ee20..c88de2db7 100644
--- a/nova/tests/api/openstack/test_ratelimiting.py
+++ b/nova/tests/api/openstack/test_ratelimiting.py
@@ -1,178 +1,321 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 OpenStack LLC.
+# All Rights Reserved.
+#
+# 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.
+
+"""
+Tests dealing with HTTP rate-limiting.
+"""
+
import httplib
+import json
import StringIO
+import stubout
import time
import webob
from nova import test
-import nova.api.openstack.ratelimiting as ratelimiting
+from nova.api.openstack import limits
+from nova.api.openstack.limits import Limit
+
+TEST_LIMITS = [
+ Limit("GET", "/delayed", "^/delayed", 1, limits.PER_MINUTE),
+ Limit("POST", "*", ".*", 7, limits.PER_MINUTE),
+ Limit("POST", "/servers", "^/servers", 3, limits.PER_MINUTE),
+ Limit("PUT", "*", "", 10, limits.PER_MINUTE),
+ Limit("PUT", "/servers", "^/servers", 5, limits.PER_MINUTE),
+]
class LimiterTest(test.TestCase):
+ """
+ Tests for the in-memory `limits.Limiter` class.
+ """
def setUp(self):
- super(LimiterTest, self).setUp()
- self.limits = {
- 'a': (5, ratelimiting.PER_SECOND),
- 'b': (5, ratelimiting.PER_MINUTE),
- 'c': (5, ratelimiting.PER_HOUR),
- 'd': (1, ratelimiting.PER_SECOND),
- 'e': (100, ratelimiting.PER_SECOND)}
- self.rl = ratelimiting.Limiter(self.limits)
-
- def exhaust(self, action, times_until_exhausted, **kwargs):
- for i in range(times_until_exhausted):
- when = self.rl.perform(action, **kwargs)
- self.assertEqual(when, None)
- num, period = self.limits[action]
- delay = period * 1.0 / num
- # Verify that we are now thoroughly delayed
- for i in range(10):
- when = self.rl.perform(action, **kwargs)
- self.assertAlmostEqual(when, delay, 2)
-
- def test_second(self):
- self.exhaust('a', 5)
- time.sleep(0.2)
- self.exhaust('a', 1)
- time.sleep(1)
- self.exhaust('a', 5)
-
- def test_minute(self):
- self.exhaust('b', 5)
-
- def test_one_per_period(self):
- def allow_once_and_deny_once():
- when = self.rl.perform('d')
- self.assertEqual(when, None)
- when = self.rl.perform('d')
- self.assertAlmostEqual(when, 1, 2)
- return when
- time.sleep(allow_once_and_deny_once())
- time.sleep(allow_once_and_deny_once())
- allow_once_and_deny_once()
-
- def test_we_can_go_indefinitely_if_we_spread_out_requests(self):
- for i in range(200):
- when = self.rl.perform('e')
- self.assertEqual(when, None)
- time.sleep(0.01)
-
- def test_users_get_separate_buckets(self):
- self.exhaust('c', 5, username='alice')
- self.exhaust('c', 5, username='bob')
- self.exhaust('c', 5, username='chuck')
- self.exhaust('c', 0, username='chuck')
- self.exhaust('c', 0, username='bob')
- self.exhaust('c', 0, username='alice')
-
-
-class FakeLimiter(object):
- """Fake Limiter class that you can tell how to behave."""
-
- def __init__(self, test):
- self._action = self._username = self._delay = None
- self.test = test
-
- def mock(self, action, username, delay):
- self._action = action
- self._username = username
- self._delay = delay
-
- def perform(self, action, username):
- self.test.assertEqual(action, self._action)
- self.test.assertEqual(username, self._username)
- return self._delay
-
-
-class WSGIAppTest(test.TestCase):
+ """Run before each test."""
+ test.TestCase.setUp(self)
+ self.time = 0.0
+ self.stubs = stubout.StubOutForTesting()
+ self.stubs.Set(limits.Limit, "_get_time", self._get_time)
+ self.limiter = limits.Limiter(TEST_LIMITS)
+
+ def tearDown(self):
+ """Run after each test."""
+ self.stubs.UnsetAll()
+
+ def _get_time(self):
+ """Return the "time" according to this test suite."""
+ return self.time
+
+ def _check(self, num, verb, url, username=None):
+ """Check and yield results from checks."""
+ for x in xrange(num):
+ yield self.limiter.check_for_delay(verb, url, username)
+
+ def _check_sum(self, num, verb, url, username=None):
+ """Check and sum results from checks."""
+ results = self._check(num, verb, url, username)
+ return sum(filter(lambda x: x != None, results))
+
+ def test_no_delay_GET(self):
+ """
+ Simple test to ensure no delay on a single call for a limit verb we
+ didn"t set.
+ """
+ delay = self.limiter.check_for_delay("GET", "/anything")
+ self.assertEqual(delay, None)
+
+ def test_no_delay_PUT(self):
+ """
+ Simple test to ensure no delay on a single call for a known limit.
+ """
+ delay = self.limiter.check_for_delay("PUT", "/anything")
+ self.assertEqual(delay, None)
+
+ def test_delay_PUT(self):
+ """
+ Ensure the 11th PUT will result in a delay of 6.0 seconds until
+ the next request will be granced.
+ """
+ expected = [None] * 10 + [6.0]
+ results = list(self._check(11, "PUT", "/anything"))
+
+ self.assertEqual(expected, results)
+
+ def test_delay_POST(self):
+ """
+ Ensure the 8th POST will result in a delay of 6.0 seconds until
+ the next request will be granced.
+ """
+ expected = [None] * 7
+ results = list(self._check(7, "POST", "/anything"))
+ self.assertEqual(expected, results)
+
+ expected = 60.0 / 7.0
+ results = self._check_sum(1, "POST", "/anything")
+ self.failUnlessAlmostEqual(expected, results, 8)
+
+ def test_delay_GET(self):
+ """
+ Ensure the 11th GET will result in NO delay.
+ """
+ expected = [None] * 11
+ results = list(self._check(11, "GET", "/anything"))
+
+ self.assertEqual(expected, results)
+
+ def test_delay_PUT_servers(self):
+ """
+ Ensure PUT on /servers limits at 5 requests, and PUT elsewhere is still
+ OK after 5 requests...but then after 11 total requests, PUT limiting
+ kicks in.
+ """
+ # First 6 requests on PUT /servers
+ expected = [None] * 5 + [12.0]
+ results = list(self._check(6, "PUT", "/servers"))
+ self.assertEqual(expected, results)
+
+ # Next 5 request on PUT /anything
+ expected = [None] * 4 + [6.0]
+ results = list(self._check(5, "PUT", "/anything"))
+ self.assertEqual(expected, results)
+
+ def test_delay_PUT_wait(self):
+ """
+ Ensure after hitting the limit and then waiting for the correct
+ amount of time, the limit will be lifted.
+ """
+ expected = [None] * 10 + [6.0]
+ results = list(self._check(11, "PUT", "/anything"))
+ self.assertEqual(expected, results)
+
+ # Advance time
+ self.time += 6.0
+
+ expected = [None, 6.0]
+ results = list(self._check(2, "PUT", "/anything"))
+ self.assertEqual(expected, results)
+
+ def test_multiple_delays(self):
+ """
+ Ensure multiple requests still get a delay.
+ """
+ expected = [None] * 10 + [6.0] * 10
+ results = list(self._check(20, "PUT", "/anything"))
+ self.assertEqual(expected, results)
+
+ self.time += 1.0
+
+ expected = [5.0] * 10
+ results = list(self._check(10, "PUT", "/anything"))
+ self.assertEqual(expected, results)
+
+ def test_multiple_users(self):
+ """
+ Tests involving multiple users.
+ """
+ # User1
+ expected = [None] * 10 + [6.0] * 10
+ results = list(self._check(20, "PUT", "/anything", "user1"))
+ self.assertEqual(expected, results)
+
+ # User2
+ expected = [None] * 10 + [6.0] * 5
+ results = list(self._check(15, "PUT", "/anything", "user2"))
+ self.assertEqual(expected, results)
+
+ self.time += 1.0
+
+ # User1 again
+ expected = [5.0] * 10
+ results = list(self._check(10, "PUT", "/anything", "user1"))
+ self.assertEqual(expected, results)
+
+ self.time += 1.0
+
+ # User1 again
+ expected = [4.0] * 5
+ results = list(self._check(5, "PUT", "/anything", "user2"))
+ self.assertEqual(expected, results)
+
+
+class WsgiLimiterTest(test.TestCase):
+ """
+ Tests for `limits.WsgiLimiter` class.
+ """
def setUp(self):
- super(WSGIAppTest, self).setUp()
- self.limiter = FakeLimiter(self)
- self.app = ratelimiting.WSGIApp(self.limiter)
+ """Run before each test."""
+ test.TestCase.setUp(self)
+ self.time = 0.0
+ self.app = limits.WsgiLimiter(TEST_LIMITS)
+ self.app._limiter._get_time = self._get_time
- def test_invalid_methods(self):
- requests = []
- for method in ['GET', 'PUT', 'DELETE']:
- req = webob.Request.blank('/limits/michael/breakdance',
- dict(REQUEST_METHOD=method))
- requests.append(req)
- for req in requests:
- self.assertEqual(req.get_response(self.app).status_int, 405)
-
- def test_invalid_urls(self):
- requests = []
- for prefix in ['limit', '', 'limiter2', 'limiter/limits', 'limiter/1']:
- req = webob.Request.blank('/%s/michael/breakdance' % prefix,
- dict(REQUEST_METHOD='POST'))
- requests.append(req)
- for req in requests:
- self.assertEqual(req.get_response(self.app).status_int, 404)
-
- def verify(self, url, username, action, delay=None):
+ def _get_time(self):
+ """Return the "time" according to this test suite."""
+ return self.time
+
+ def _request_data(self, verb, path):
+ """Get data decribing a limit request verb/path."""
+ return json.dumps({"verb":verb, "path":path})
+
+ def _request(self, verb, url, username=None):
"""Make sure that POSTing to the given url causes the given username
to perform the given action. Make the internal rate limiter return
delay and make sure that the WSGI app returns the correct response.
"""
- req = webob.Request.blank(url, dict(REQUEST_METHOD='POST'))
- self.limiter.mock(action, username, delay)
- resp = req.get_response(self.app)
- if not delay:
- self.assertEqual(resp.status_int, 200)
+ if username:
+ request = webob.Request.blank("/%s" % username)
else:
- self.assertEqual(resp.status_int, 403)
- self.assertEqual(resp.headers['X-Wait-Seconds'], "%.2f" % delay)
+ request = webob.Request.blank("/")
+
+ request.method = "POST"
+ request.body = self._request_data(verb, url)
+ response = request.get_response(self.app)
+
+ if "X-Wait-Seconds" in response.headers:
+ self.assertEqual(response.status_int, 403)
+ return response.headers["X-Wait-Seconds"]
+
+ self.assertEqual(response.status_int, 204)
- def test_good_urls(self):
- self.verify('/limiter/michael/hoot', 'michael', 'hoot')
+ def test_invalid_methods(self):
+ """Only POSTs should work."""
+ requests = []
+ for method in ["GET", "PUT", "DELETE", "HEAD", "OPTIONS"]:
+ request = webob.Request.blank("/")
+ request.body = self._request_data("GET", "/something")
+ response = request.get_response(self.app)
+ self.assertEqual(response.status_int, 405)
+
+ def test_good_url(self):
+ delay = self._request("GET", "/something")
+ self.assertEqual(delay, None)
def test_escaping(self):
- self.verify('/limiter/michael/jump%20up', 'michael', 'jump up')
+ delay = self._request("GET", "/something/jump%20up")
+ self.assertEqual(delay, None)
def test_response_to_delays(self):
- self.verify('/limiter/michael/hoot', 'michael', 'hoot', 1)
- self.verify('/limiter/michael/hoot', 'michael', 'hoot', 1.56)
- self.verify('/limiter/michael/hoot', 'michael', 'hoot', 1000)
+ delay = self._request("GET", "/delayed")
+ self.assertEqual(delay, None)
+
+ delay = self._request("GET", "/delayed")
+ self.assertEqual(delay, '60.00')
+
+ def test_response_to_delays_usernames(self):
+ delay = self._request("GET", "/delayed", "user1")
+ self.assertEqual(delay, None)
+
+ delay = self._request("GET", "/delayed", "user2")
+ self.assertEqual(delay, None)
+
+ delay = self._request("GET", "/delayed", "user1")
+ self.assertEqual(delay, '60.00')
+
+ delay = self._request("GET", "/delayed", "user2")
+ self.assertEqual(delay, '60.00')
class FakeHttplibSocket(object):
- """a fake socket implementation for httplib.HTTPResponse, trivial"""
+ """
+ Fake `httplib.HTTPResponse` replacement.
+ """
def __init__(self, response_string):
+ """Initialize new `FakeHttplibSocket`."""
self._buffer = StringIO.StringIO(response_string)
def makefile(self, _mode, _other):
- """Returns the socket's internal buffer"""
+ """Returns the socket's internal buffer."""
return self._buffer
class FakeHttplibConnection(object):
- """A fake httplib.HTTPConnection
-
- Requests made via this connection actually get translated and routed into
- our WSGI app, we then wait for the response and turn it back into
- an httplib.HTTPResponse.
"""
- def __init__(self, app, host, is_secure=False):
+ Fake `httplib.HTTPConnection`.
+ """
+
+ def __init__(self, app, host):
+ """
+ Initialize `FakeHttplibConnection`.
+ """
self.app = app
self.host = host
- def request(self, method, path, data='', headers={}):
+ def request(self, method, path, body="", headers={}):
+ """
+ Requests made via this connection actually get translated and routed into
+ our WSGI app, we then wait for the response and turn it back into
+ an `httplib.HTTPResponse`.
+ """
req = webob.Request.blank(path)
req.method = method
- req.body = data
req.headers = headers
req.host = self.host
- # Call the WSGI app, get the HTTP response
+ req.body = body
+
resp = str(req.get_response(self.app))
- # For some reason, the response doesn't have "HTTP/1.0 " prepended; I
- # guess that's a function the web server usually provides.
resp = "HTTP/1.0 %s" % resp
sock = FakeHttplibSocket(resp)
self.http_response = httplib.HTTPResponse(sock)
self.http_response.begin()
def getresponse(self):
+ """Return our generated response from the request."""
return self.http_response
@@ -208,36 +351,36 @@ def wire_HTTPConnection_to_WSGI(host, app):
httplib.HTTPConnection = HTTPConnectionDecorator(httplib.HTTPConnection)
-class WSGIAppProxyTest(test.TestCase):
+class WsgiLimiterProxyTest(test.TestCase):
+ """
+ Tests for the `limits.WsgiLimiterProxy` class.
+ """
def setUp(self):
- """Our WSGIAppProxy is going to call across an HTTPConnection to a
- WSGIApp running a limiter. The proxy will send input, and the proxy
- should receive that same input, pass it to the limiter who gives a
- result, and send the expected result back.
-
- The HTTPConnection isn't real -- it's monkeypatched to point straight
- at the WSGIApp. And the limiter isn't real -- it's a fake that
- behaves the way we tell it to.
"""
- super(WSGIAppProxyTest, self).setUp()
- self.limiter = FakeLimiter(self)
- app = ratelimiting.WSGIApp(self.limiter)
- wire_HTTPConnection_to_WSGI('100.100.100.100:80', app)
- self.proxy = ratelimiting.WSGIAppProxy('100.100.100.100:80')
+ Do some nifty HTTP/WSGI magic which allows for WSGI to be called
+ directly by something like the `httplib` library.
+ """
+ test.TestCase.setUp(self)
+ self.time = 0.0
+ self.app = limits.WsgiLimiter(TEST_LIMITS)
+ self.app._limiter._get_time = self._get_time
+ wire_HTTPConnection_to_WSGI("169.254.0.1:80", self.app)
+ self.proxy = limits.WsgiLimiterProxy("169.254.0.1:80")
+
+ def _get_time(self):
+ """Return the "time" according to this test suite."""
+ return self.time
def test_200(self):
- self.limiter.mock('conquer', 'caesar', None)
- when = self.proxy.perform('conquer', 'caesar')
- self.assertEqual(when, None)
+ """Successful request test."""
+ delay = self.proxy.check_for_delay("GET", "/anything")
+ self.assertEqual(delay, None)
def test_403(self):
- self.limiter.mock('grumble', 'proletariat', 1.5)
- when = self.proxy.perform('grumble', 'proletariat')
- self.assertEqual(when, 1.5)
-
- def test_failure(self):
- def shouldRaise():
- self.limiter.mock('murder', 'brutus', None)
- self.proxy.perform('stab', 'brutus')
- self.assertRaises(AssertionError, shouldRaise)
+ """Forbidden request test."""
+ delay = self.proxy.check_for_delay("GET", "/delayed")
+ self.assertEqual(delay, None)
+
+ delay = self.proxy.check_for_delay("GET", "/delayed")
+ self.assertEqual(delay, '60.00')
--
cgit
From f1acc3d199a1a92b531a3e74ed54a8b2fcdb999c Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Tue, 15 Mar 2011 13:52:03 -0700
Subject: Now that the fix for 732866, stop working around the bug
---
nova/tests/integrated/api/client.py | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/nova/tests/integrated/api/client.py b/nova/tests/integrated/api/client.py
index 568e8c17e..fc7c344e7 100644
--- a/nova/tests/integrated/api/client.py
+++ b/nova/tests/integrated/api/client.py
@@ -108,10 +108,7 @@ class TestOpenStackClient(object):
http_status = response.status
LOG.debug(_("%(auth_uri)s => code %(http_status)s") % locals())
- # Until bug732866 is fixed, we can't check this properly...
- # bug732866
- #if http_status == 401:
- if http_status != 204:
+ if http_status == 401:
raise OpenStackApiAuthenticationException(response=response)
auth_headers = {}
--
cgit
From 1b477c2225816ea8f05595a8812932d516828e01 Mon Sep 17 00:00:00 2001
From: Brian Lamar
Date: Tue, 15 Mar 2011 17:47:34 -0400
Subject: pep8 fixes
---
nova/api/openstack/limits.py | 43 +++++++++++++--------------
nova/tests/api/openstack/test_ratelimiting.py | 19 ++++++------
2 files changed, 30 insertions(+), 32 deletions(-)
diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py
index 4f64cab3c..b1e633330 100644
--- a/nova/api/openstack/limits.py
+++ b/nova/api/openstack/limits.py
@@ -58,12 +58,12 @@ class LimitsController(Controller):
rate_limits = req.environ.get("nova.limits", {})
return {
- "limits" : {
- "rate" : rate_limits,
- "absolute" : abs_limits,
+ "limits": {
+ "rate": rate_limits,
+ "absolute": abs_limits,
},
}
-
+
class Limit(object):
"""
@@ -71,10 +71,10 @@ class Limit(object):
"""
UNITS = {
- 1 : "SECOND",
- 60 : "MINUTE",
- 60 * 60 : "HOUR",
- 60 * 60 * 24 : "DAY",
+ 1: "SECOND",
+ 60: "MINUTE",
+ 60 * 60: "HOUR",
+ 60 * 60 * 24: "DAY",
}
def __init__(self, verb, uri, regex, value, unit):
@@ -137,14 +137,13 @@ class Limit(object):
cap = self.capacity
water = self.water_level
val = self.value
-
+
self.remaining = math.floor((cap - water) / cap * val)
- print "Remaining:", self.remaining
self.next_request = now
def _get_time(self):
"""Retrieve the current time. Broken out for testability."""
- return time.time()
+ return time.time()
def display_unit(self):
"""Display the string name of the unit."""
@@ -153,17 +152,15 @@ class Limit(object):
def display(self):
"""Return a useful representation of this class."""
return {
- "verb" : self.verb,
- "uri" : self.uri,
- "regex" : self.regex,
- "value" : self.value,
- "remaining" : int(self.remaining),
- "unit" : self.display_unit(),
- "resetTime" : int(self.next_request or self._get_time()),
+ "verb": self.verb,
+ "uri": self.uri,
+ "regex": self.regex,
+ "value": self.value,
+ "remaining": int(self.remaining),
+ "unit": self.display_unit(),
+ "resetTime": int(self.next_request or self._get_time()),
}
-
-
# "Limit" format is a dictionary with the HTTP verb, human-readable URI,
# a regular-expression to match, value and unit of measure (PER_DAY, etc.)
@@ -324,11 +321,11 @@ class WsgiLimiterProxy(object):
self.limiter_address = limiter_address
def check_for_delay(self, verb, path, username=None):
- body = json.dumps({"verb":verb,"path":path})
- headers = {"Content-Type" : "application/json"}
+ body = json.dumps({"verb": verb, "path": path})
+ headers = {"Content-Type": "application/json"}
conn = httplib.HTTPConnection(self.limiter_address)
-
+
if username:
conn.request("POST", "/%s" % (username), body, headers)
else:
diff --git a/nova/tests/api/openstack/test_ratelimiting.py b/nova/tests/api/openstack/test_ratelimiting.py
index c88de2db7..a706364b4 100644
--- a/nova/tests/api/openstack/test_ratelimiting.py
+++ b/nova/tests/api/openstack/test_ratelimiting.py
@@ -39,6 +39,7 @@ TEST_LIMITS = [
Limit("PUT", "/servers", "^/servers", 5, limits.PER_MINUTE),
]
+
class LimiterTest(test.TestCase):
"""
Tests for the in-memory `limits.Limiter` class.
@@ -107,7 +108,7 @@ class LimiterTest(test.TestCase):
expected = 60.0 / 7.0
results = self._check_sum(1, "POST", "/anything")
self.failUnlessAlmostEqual(expected, results, 8)
-
+
def test_delay_GET(self):
"""
Ensure the 11th GET will result in NO delay.
@@ -144,7 +145,7 @@ class LimiterTest(test.TestCase):
# Advance time
self.time += 6.0
-
+
expected = [None, 6.0]
results = list(self._check(2, "PUT", "/anything"))
self.assertEqual(expected, results)
@@ -190,8 +191,8 @@ class LimiterTest(test.TestCase):
expected = [4.0] * 5
results = list(self._check(5, "PUT", "/anything", "user2"))
self.assertEqual(expected, results)
-
-
+
+
class WsgiLimiterTest(test.TestCase):
"""
Tests for `limits.WsgiLimiter` class.
@@ -210,7 +211,7 @@ class WsgiLimiterTest(test.TestCase):
def _request_data(self, verb, path):
"""Get data decribing a limit request verb/path."""
- return json.dumps({"verb":verb, "path":path})
+ return json.dumps({"verb": verb, "path": path})
def _request(self, verb, url, username=None):
"""Make sure that POSTing to the given url causes the given username
@@ -221,7 +222,7 @@ class WsgiLimiterTest(test.TestCase):
request = webob.Request.blank("/%s" % username)
else:
request = webob.Request.blank("/")
-
+
request.method = "POST"
request.body = self._request_data(verb, url)
response = request.get_response(self.app)
@@ -229,7 +230,7 @@ class WsgiLimiterTest(test.TestCase):
if "X-Wait-Seconds" in response.headers:
self.assertEqual(response.status_int, 403)
return response.headers["X-Wait-Seconds"]
-
+
self.assertEqual(response.status_int, 204)
def test_invalid_methods(self):
@@ -298,8 +299,8 @@ class FakeHttplibConnection(object):
def request(self, method, path, body="", headers={}):
"""
- Requests made via this connection actually get translated and routed into
- our WSGI app, we then wait for the response and turn it back into
+ Requests made via this connection actually get translated and routed
+ into our WSGI app, we then wait for the response and turn it back into
an `httplib.HTTPResponse`.
"""
req = webob.Request.blank(path)
--
cgit
From 6d984c3097252f9f97ef10e48be390fdf756b391 Mon Sep 17 00:00:00 2001
From: Ken Pepple
Date: Tue, 15 Mar 2011 16:08:22 -0700
Subject: wrap errors getting image ids from local image store
---
nova/image/local.py | 14 ++++++++++++--
nova/tests/api/openstack/test_images.py | 7 +++++++
2 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/nova/image/local.py b/nova/image/local.py
index c4ac3baaa..ef92a35b5 100644
--- a/nova/image/local.py
+++ b/nova/image/local.py
@@ -20,8 +20,9 @@ import os.path
import random
import shutil
-from nova import flags
from nova import exception
+from nova import flags
+from nova import log as logging
from nova.image import service
@@ -29,6 +30,8 @@ FLAGS = flags.FLAGS
flags.DEFINE_string('images_path', '$state_path/images',
'path to decrypted images')
+LOG = logging.getLogger('nova.image.local')
+
class LocalImageService(service.BaseImageService):
"""Image service storing images to local disk.
@@ -47,7 +50,14 @@ class LocalImageService(service.BaseImageService):
def _ids(self):
"""The list of all image ids."""
- return [int(i, 16) for i in os.listdir(self._path)]
+ images = []
+ for i in os.listdir(self._path):
+ try:
+ images.append(int(i, 16))
+ except:
+ LOG.debug(
+ _("%s is not in correct directory naming format" % i))
+ return images
def index(self, context):
return [dict(image_id=i['id'], name=i.get('name'))
diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py
index 76f758929..2c4918117 100644
--- a/nova/tests/api/openstack/test_images.py
+++ b/nova/tests/api/openstack/test_images.py
@@ -151,6 +151,13 @@ class LocalImageServiceTest(test.TestCase,
self.stubs.UnsetAll()
super(LocalImageServiceTest, self).tearDown()
+ def test_get_all_ids_with_incorrect_directory_formats(self):
+ # create some old-style image directories (starting with 'ami-')
+ for x in [1, 2, 3]:
+ tempfile.mkstemp(prefix='ami-', dir=self.tempdir)
+ found_images = self.service._ids()
+ self.assertEqual(True, isinstance(found_images, list))
+
class GlanceImageServiceTest(test.TestCase,
BaseImageServiceTests):
--
cgit
From 5e45d0ba921566e98817cb9e62e383f84c30c5f6 Mon Sep 17 00:00:00 2001
From: Brian Lamar
Date: Tue, 15 Mar 2011 20:51:17 -0400
Subject: Limits controller and testing with XML and JSON serialization.
---
nova/api/openstack/limits.py | 42 ++-
nova/tests/api/openstack/test_limits.py | 524 ++++++++++++++++++++++++++
nova/tests/api/openstack/test_ratelimiting.py | 387 -------------------
nova/wsgi.py | 1 +
4 files changed, 556 insertions(+), 398 deletions(-)
create mode 100644 nova/tests/api/openstack/test_limits.py
delete mode 100644 nova/tests/api/openstack/test_ratelimiting.py
diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py
index b1e633330..57e6bfcc2 100644
--- a/nova/api/openstack/limits.py
+++ b/nova/api/openstack/limits.py
@@ -50,12 +50,24 @@ class LimitsController(Controller):
Controller for accessing limits in the OpenStack API.
"""
+ _serialization_metadata = {
+ "application/xml": {
+ "attributes": {
+ "limit": ["verb", "URI", "regex", "value", "unit",
+ "resetTime", "remaining", "name"],
+ },
+ "plurals" : {
+ "rate" : "limit",
+ },
+ },
+ }
+
def index(self, req):
"""
Return all global and rate limit information.
"""
abs_limits = {}
- rate_limits = req.environ.get("nova.limits", {})
+ rate_limits = req.environ.get("nova.limits", [])
return {
"limits": {
@@ -92,6 +104,7 @@ class Limit(object):
self.regex = regex
self.value = int(value)
self.unit = unit
+ self.unit_string = self.display_unit().lower()
self.remaining = int(value)
if value <= 0:
@@ -101,8 +114,10 @@ class Limit(object):
self.next_request = None
self.water_level = 0
- self.capacity = float(self.unit)
+ self.capacity = self.unit
self.request_value = float(self.capacity) / float(self.value)
+ self.error_message = _("Only %(value)s %(verb)s request(s) can be "\
+ "made to %(uri)s every %(unit_string)s." % self.__dict__)
def __call__(self, verb, url):
"""
@@ -153,7 +168,7 @@ class Limit(object):
"""Return a useful representation of this class."""
return {
"verb": self.verb,
- "uri": self.uri,
+ "URI": self.uri,
"regex": self.regex,
"value": self.value,
"remaining": int(self.remaining),
@@ -204,13 +219,12 @@ class RateLimitingMiddleware(Middleware):
url = req.url
username = req.environ["nova.context"].user_id
- delay = self._limiter.check_for_delay(verb, url, username)
+ delay, error = self._limiter.check_for_delay(verb, url, username)
if delay:
msg = "This request was rate-limited."
- details = "Error details."
retry = time.time() + delay
- return faults.OverLimitFault(msg, details, retry)
+ return faults.OverLimitFault(msg, error, retry)
req.environ["nova.limits"] = self._limiter.get_limits(username)
@@ -240,13 +254,15 @@ class Limiter(object):
def check_for_delay(self, verb, url, username=None):
"""
Check the given verb/user/user triplet for limit.
+
+ @return: Tuple of delay (in seconds) and error message (or None, None)
"""
def _get_delay_list():
"""Yield limit delays."""
for limit in self.levels[username]:
delay = limit(verb, url)
if delay:
- yield delay
+ yield delay, limit.error_message
delays = list(_get_delay_list())
@@ -254,6 +270,8 @@ class Limiter(object):
delays.sort()
return delays[0]
+ return None, None
+
class WsgiLimiter(object):
"""
@@ -298,11 +316,11 @@ class WsgiLimiter(object):
verb = info.get("verb")
path = info.get("path")
- delay = self._limiter.check_for_delay(verb, path, username)
+ delay, error = self._limiter.check_for_delay(verb, path, username)
if delay:
headers = {"X-Wait-Seconds": "%.2f" % delay}
- return webob.exc.HTTPForbidden(headers=headers)
+ return webob.exc.HTTPForbidden(headers=headers, explanation=error)
else:
return webob.exc.HTTPNoContent()
@@ -333,7 +351,9 @@ class WsgiLimiterProxy(object):
resp = conn.getresponse()
+ print resp
+
if 200 >= resp.status < 300:
- return None
+ return None, None
- return resp.getheader("X-Wait-Seconds")
+ return resp.getheader("X-Wait-Seconds"), resp.read() or None
diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py
new file mode 100644
index 000000000..cf4389c1d
--- /dev/null
+++ b/nova/tests/api/openstack/test_limits.py
@@ -0,0 +1,524 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 OpenStack LLC.
+# All Rights Reserved.
+#
+# 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.
+
+"""
+Tests dealing with HTTP rate-limiting.
+"""
+
+import httplib
+import json
+import StringIO
+import stubout
+import time
+import webob
+
+from xml.dom.minidom import parseString
+
+from nova import test
+from nova.api.openstack import limits
+from nova.api.openstack.limits import Limit
+
+
+TEST_LIMITS = [
+ Limit("GET", "/delayed", "^/delayed", 1, limits.PER_MINUTE),
+ Limit("POST", "*", ".*", 7, limits.PER_MINUTE),
+ Limit("POST", "/servers", "^/servers", 3, limits.PER_MINUTE),
+ Limit("PUT", "*", "", 10, limits.PER_MINUTE),
+ Limit("PUT", "/servers", "^/servers", 5, limits.PER_MINUTE),
+]
+
+
+class LimitsControllerTest(test.TestCase):
+ """
+ Tests for `limits.LimitsController` class.
+ """
+
+ def setUp(self):
+ """Run before each test."""
+ test.TestCase.setUp(self)
+ self.time = 0.0
+ self.stubs = stubout.StubOutForTesting()
+ self.stubs.Set(limits.Limit, "_get_time", self._get_time)
+ self.controller = limits.LimitsController()
+
+ def tearDown(self):
+ """Run after each test."""
+ self.stubs.UnsetAll()
+ test.TestCase.tearDown(self)
+
+ def _get_time(self):
+ """Return the "time" according to this test suite."""
+ return self.time
+
+ def _get_index_request(self, accept_header="application/json"):
+ """Helper to set routing arguments."""
+ request = webob.Request.blank("/")
+ request.accept = accept_header
+ request.environ["wsgiorg.routing_args"] = (None, {
+ "action": "index",
+ "controller": "",
+ })
+ return request
+
+ def _populate_limits(self, request):
+ """Put limit info into a request."""
+ limits = [
+ Limit("GET", "*", ".*", 10, 60).display(),
+ Limit("POST", "*", ".*", 5, 60 * 60).display(),
+ ]
+ request.environ["nova.limits"] = limits
+ return request
+
+ def test_empty_index_json(self):
+ """Test getting empty limit details in JSON."""
+ request = self._get_index_request()
+ response = request.get_response(self.controller)
+ expected = {
+ "limits": {
+ "rate": [],
+ "absolute": {},
+ },
+ }
+ body = json.loads(response.body)
+ self.assertEqual(expected, body)
+
+ def test_index_json(self):
+ """Test getting limit details in JSON."""
+ request = self._get_index_request()
+ request = self._populate_limits(request)
+ response = request.get_response(self.controller)
+ expected = {
+ "limits": {
+ "rate": [{
+ "regex": ".*",
+ "resetTime": 0,
+ "URI": "*",
+ "value": 10,
+ "verb": "GET",
+ "remaining": 10,
+ "unit": "MINUTE",
+ },
+ {
+ "regex": ".*",
+ "resetTime": 0,
+ "URI": "*",
+ "value": 5,
+ "verb": "POST",
+ "remaining": 5,
+ "unit": "HOUR",
+ }],
+ "absolute": {},
+ },
+ }
+ body = json.loads(response.body)
+ self.assertEqual(expected, body)
+
+ def test_empty_index_xml(self):
+ """Test getting limit details in XML."""
+ request = self._get_index_request("application/xml")
+ response = request.get_response(self.controller)
+
+ expected = ""
+ body = response.body.replace("\n","").replace(" ", "")
+
+ self.assertEqual(expected, body)
+
+ def test_index_xml(self):
+ """Test getting limit details in XML."""
+ request = self._get_index_request("application/xml")
+ request = self._populate_limits(request)
+ response = request.get_response(self.controller)
+
+ expected = parseString("""
+
+
+
+
+
+
+
+ """.replace(" ", ""))
+ body = parseString(response.body.replace(" ", ""))
+
+ self.assertEqual(expected.toxml(), body.toxml())
+
+
+class LimiterTest(test.TestCase):
+ """
+ Tests for the in-memory `limits.Limiter` class.
+ """
+
+ def setUp(self):
+ """Run before each test."""
+ test.TestCase.setUp(self)
+ self.time = 0.0
+ self.stubs = stubout.StubOutForTesting()
+ self.stubs.Set(limits.Limit, "_get_time", self._get_time)
+ self.limiter = limits.Limiter(TEST_LIMITS)
+
+ def tearDown(self):
+ """Run after each test."""
+ self.stubs.UnsetAll()
+ test.TestCase.tearDown(self)
+
+ def _get_time(self):
+ """Return the "time" according to this test suite."""
+ return self.time
+
+ def _check(self, num, verb, url, username=None):
+ """Check and yield results from checks."""
+ for x in xrange(num):
+ yield self.limiter.check_for_delay(verb, url, username)[0]
+
+ def _check_sum(self, num, verb, url, username=None):
+ """Check and sum results from checks."""
+ results = self._check(num, verb, url, username)
+ return sum(filter(lambda x: x != None, results))
+
+ def test_no_delay_GET(self):
+ """
+ Simple test to ensure no delay on a single call for a limit verb we
+ didn"t set.
+ """
+ delay = self.limiter.check_for_delay("GET", "/anything")
+ self.assertEqual(delay, (None, None))
+
+ def test_no_delay_PUT(self):
+ """
+ Simple test to ensure no delay on a single call for a known limit.
+ """
+ delay = self.limiter.check_for_delay("PUT", "/anything")
+ self.assertEqual(delay, (None, None))
+
+ def test_delay_PUT(self):
+ """
+ Ensure the 11th PUT will result in a delay of 6.0 seconds until
+ the next request will be granced.
+ """
+ expected = [None] * 10 + [6.0]
+ results = list(self._check(11, "PUT", "/anything"))
+
+ self.assertEqual(expected, results)
+
+ def test_delay_POST(self):
+ """
+ Ensure the 8th POST will result in a delay of 6.0 seconds until
+ the next request will be granced.
+ """
+ expected = [None] * 7
+ results = list(self._check(7, "POST", "/anything"))
+ self.assertEqual(expected, results)
+
+ expected = 60.0 / 7.0
+ results = self._check_sum(1, "POST", "/anything")
+ self.failUnlessAlmostEqual(expected, results, 8)
+
+ def test_delay_GET(self):
+ """
+ Ensure the 11th GET will result in NO delay.
+ """
+ expected = [None] * 11
+ results = list(self._check(11, "GET", "/anything"))
+
+ self.assertEqual(expected, results)
+
+ def test_delay_PUT_servers(self):
+ """
+ Ensure PUT on /servers limits at 5 requests, and PUT elsewhere is still
+ OK after 5 requests...but then after 11 total requests, PUT limiting
+ kicks in.
+ """
+ # First 6 requests on PUT /servers
+ expected = [None] * 5 + [12.0]
+ results = list(self._check(6, "PUT", "/servers"))
+ self.assertEqual(expected, results)
+
+ # Next 5 request on PUT /anything
+ expected = [None] * 4 + [6.0]
+ results = list(self._check(5, "PUT", "/anything"))
+ self.assertEqual(expected, results)
+
+ def test_delay_PUT_wait(self):
+ """
+ Ensure after hitting the limit and then waiting for the correct
+ amount of time, the limit will be lifted.
+ """
+ expected = [None] * 10 + [6.0]
+ results = list(self._check(11, "PUT", "/anything"))
+ self.assertEqual(expected, results)
+
+ # Advance time
+ self.time += 6.0
+
+ expected = [None, 6.0]
+ results = list(self._check(2, "PUT", "/anything"))
+ self.assertEqual(expected, results)
+
+ def test_multiple_delays(self):
+ """
+ Ensure multiple requests still get a delay.
+ """
+ expected = [None] * 10 + [6.0] * 10
+ results = list(self._check(20, "PUT", "/anything"))
+ self.assertEqual(expected, results)
+
+ self.time += 1.0
+
+ expected = [5.0] * 10
+ results = list(self._check(10, "PUT", "/anything"))
+ self.assertEqual(expected, results)
+
+ def test_multiple_users(self):
+ """
+ Tests involving multiple users.
+ """
+ # User1
+ expected = [None] * 10 + [6.0] * 10
+ results = list(self._check(20, "PUT", "/anything", "user1"))
+ self.assertEqual(expected, results)
+
+ # User2
+ expected = [None] * 10 + [6.0] * 5
+ results = list(self._check(15, "PUT", "/anything", "user2"))
+ self.assertEqual(expected, results)
+
+ self.time += 1.0
+
+ # User1 again
+ expected = [5.0] * 10
+ results = list(self._check(10, "PUT", "/anything", "user1"))
+ self.assertEqual(expected, results)
+
+ self.time += 1.0
+
+ # User1 again
+ expected = [4.0] * 5
+ results = list(self._check(5, "PUT", "/anything", "user2"))
+ self.assertEqual(expected, results)
+
+
+class WsgiLimiterTest(test.TestCase):
+ """
+ Tests for `limits.WsgiLimiter` class.
+ """
+
+ def setUp(self):
+ """Run before each test."""
+ test.TestCase.setUp(self)
+ self.time = 0.0
+ self.stubs = stubout.StubOutForTesting()
+ self.stubs.Set(limits.Limit, "_get_time", self._get_time)
+ self.app = limits.WsgiLimiter(TEST_LIMITS)
+
+ def tearDown(self):
+ """Run after each test."""
+ self.stubs.UnsetAll()
+ test.TestCase.tearDown(self)
+
+ def _get_time(self):
+ """Return the "time" according to this test suite."""
+ return self.time
+
+ def _request_data(self, verb, path):
+ """Get data decribing a limit request verb/path."""
+ return json.dumps({"verb": verb, "path": path})
+
+ def _request(self, verb, url, username=None):
+ """Make sure that POSTing to the given url causes the given username
+ to perform the given action. Make the internal rate limiter return
+ delay and make sure that the WSGI app returns the correct response.
+ """
+ if username:
+ request = webob.Request.blank("/%s" % username)
+ else:
+ request = webob.Request.blank("/")
+
+ request.method = "POST"
+ request.body = self._request_data(verb, url)
+ response = request.get_response(self.app)
+
+ if "X-Wait-Seconds" in response.headers:
+ self.assertEqual(response.status_int, 403)
+ return response.headers["X-Wait-Seconds"]
+
+ self.assertEqual(response.status_int, 204)
+
+ def test_invalid_methods(self):
+ """Only POSTs should work."""
+ requests = []
+ for method in ["GET", "PUT", "DELETE", "HEAD", "OPTIONS"]:
+ request = webob.Request.blank("/")
+ request.body = self._request_data("GET", "/something")
+ response = request.get_response(self.app)
+ self.assertEqual(response.status_int, 405)
+
+ def test_good_url(self):
+ delay = self._request("GET", "/something")
+ self.assertEqual(delay, None)
+
+ def test_escaping(self):
+ delay = self._request("GET", "/something/jump%20up")
+ self.assertEqual(delay, None)
+
+ def test_response_to_delays(self):
+ delay = self._request("GET", "/delayed")
+ self.assertEqual(delay, None)
+
+ delay = self._request("GET", "/delayed")
+ self.assertEqual(delay, '60.00')
+
+ def test_response_to_delays_usernames(self):
+ delay = self._request("GET", "/delayed", "user1")
+ self.assertEqual(delay, None)
+
+ delay = self._request("GET", "/delayed", "user2")
+ self.assertEqual(delay, None)
+
+ delay = self._request("GET", "/delayed", "user1")
+ self.assertEqual(delay, '60.00')
+
+ delay = self._request("GET", "/delayed", "user2")
+ self.assertEqual(delay, '60.00')
+
+
+class FakeHttplibSocket(object):
+ """
+ Fake `httplib.HTTPResponse` replacement.
+ """
+
+ def __init__(self, response_string):
+ """Initialize new `FakeHttplibSocket`."""
+ self._buffer = StringIO.StringIO(response_string)
+
+ def makefile(self, _mode, _other):
+ """Returns the socket's internal buffer."""
+ return self._buffer
+
+
+class FakeHttplibConnection(object):
+ """
+ Fake `httplib.HTTPConnection`.
+ """
+
+ def __init__(self, app, host):
+ """
+ Initialize `FakeHttplibConnection`.
+ """
+ self.app = app
+ self.host = host
+
+ def request(self, method, path, body="", headers={}):
+ """
+ Requests made via this connection actually get translated and routed
+ into our WSGI app, we then wait for the response and turn it back into
+ an `httplib.HTTPResponse`.
+ """
+ req = webob.Request.blank(path)
+ req.method = method
+ req.headers = headers
+ req.host = self.host
+ req.body = body
+
+ resp = str(req.get_response(self.app))
+ resp = "HTTP/1.0 %s" % resp
+ sock = FakeHttplibSocket(resp)
+ self.http_response = httplib.HTTPResponse(sock)
+ self.http_response.begin()
+
+ def getresponse(self):
+ """Return our generated response from the request."""
+ return self.http_response
+
+
+def wire_HTTPConnection_to_WSGI(host, app):
+ """Monkeypatches HTTPConnection so that if you try to connect to host, you
+ are instead routed straight to the given WSGI app.
+
+ After calling this method, when any code calls
+
+ httplib.HTTPConnection(host)
+
+ the connection object will be a fake. Its requests will be sent directly
+ to the given WSGI app rather than through a socket.
+
+ Code connecting to hosts other than host will not be affected.
+
+ This method may be called multiple times to map different hosts to
+ different apps.
+ """
+ class HTTPConnectionDecorator(object):
+ """Wraps the real HTTPConnection class so that when you instantiate
+ the class you might instead get a fake instance."""
+
+ def __init__(self, wrapped):
+ self.wrapped = wrapped
+
+ def __call__(self, connection_host, *args, **kwargs):
+ if connection_host == host:
+ return FakeHttplibConnection(app, host)
+ else:
+ return self.wrapped(connection_host, *args, **kwargs)
+
+ httplib.HTTPConnection = HTTPConnectionDecorator(httplib.HTTPConnection)
+
+
+class WsgiLimiterProxyTest(test.TestCase):
+ """
+ Tests for the `limits.WsgiLimiterProxy` class.
+ """
+
+ def setUp(self):
+ """
+ Do some nifty HTTP/WSGI magic which allows for WSGI to be called
+ directly by something like the `httplib` library.
+ """
+ test.TestCase.setUp(self)
+ self.time = 0.0
+ self.stubs = stubout.StubOutForTesting()
+ self.stubs.Set(limits.Limit, "_get_time", self._get_time)
+ self.app = limits.WsgiLimiter(TEST_LIMITS)
+ wire_HTTPConnection_to_WSGI("169.254.0.1:80", self.app)
+ self.proxy = limits.WsgiLimiterProxy("169.254.0.1:80")
+
+ def tearDown(self):
+ """Run after each test."""
+ self.stubs.UnsetAll()
+ test.TestCase.tearDown(self)
+
+ def _get_time(self):
+ """Return the "time" according to this test suite."""
+ return self.time
+
+ def test_200(self):
+ """Successful request test."""
+ delay = self.proxy.check_for_delay("GET", "/anything")
+ self.assertEqual(delay, (None, None))
+
+ def test_403(self):
+ """Forbidden request test."""
+ delay = self.proxy.check_for_delay("GET", "/delayed")
+ self.assertEqual(delay, (None, None))
+
+ delay, error = self.proxy.check_for_delay("GET", "/delayed")
+ error = error.strip()
+
+ expected = ("60.00", "403 Forbidden\n\nOnly 1 GET request(s) can be "\
+ "made to /delayed every minute.")
+
+ self.assertEqual((delay, error), expected)
diff --git a/nova/tests/api/openstack/test_ratelimiting.py b/nova/tests/api/openstack/test_ratelimiting.py
deleted file mode 100644
index a706364b4..000000000
--- a/nova/tests/api/openstack/test_ratelimiting.py
+++ /dev/null
@@ -1,387 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-"""
-Tests dealing with HTTP rate-limiting.
-"""
-
-import httplib
-import json
-import StringIO
-import stubout
-import time
-import webob
-
-from nova import test
-from nova.api.openstack import limits
-from nova.api.openstack.limits import Limit
-
-
-TEST_LIMITS = [
- Limit("GET", "/delayed", "^/delayed", 1, limits.PER_MINUTE),
- Limit("POST", "*", ".*", 7, limits.PER_MINUTE),
- Limit("POST", "/servers", "^/servers", 3, limits.PER_MINUTE),
- Limit("PUT", "*", "", 10, limits.PER_MINUTE),
- Limit("PUT", "/servers", "^/servers", 5, limits.PER_MINUTE),
-]
-
-
-class LimiterTest(test.TestCase):
- """
- Tests for the in-memory `limits.Limiter` class.
- """
-
- def setUp(self):
- """Run before each test."""
- test.TestCase.setUp(self)
- self.time = 0.0
- self.stubs = stubout.StubOutForTesting()
- self.stubs.Set(limits.Limit, "_get_time", self._get_time)
- self.limiter = limits.Limiter(TEST_LIMITS)
-
- def tearDown(self):
- """Run after each test."""
- self.stubs.UnsetAll()
-
- def _get_time(self):
- """Return the "time" according to this test suite."""
- return self.time
-
- def _check(self, num, verb, url, username=None):
- """Check and yield results from checks."""
- for x in xrange(num):
- yield self.limiter.check_for_delay(verb, url, username)
-
- def _check_sum(self, num, verb, url, username=None):
- """Check and sum results from checks."""
- results = self._check(num, verb, url, username)
- return sum(filter(lambda x: x != None, results))
-
- def test_no_delay_GET(self):
- """
- Simple test to ensure no delay on a single call for a limit verb we
- didn"t set.
- """
- delay = self.limiter.check_for_delay("GET", "/anything")
- self.assertEqual(delay, None)
-
- def test_no_delay_PUT(self):
- """
- Simple test to ensure no delay on a single call for a known limit.
- """
- delay = self.limiter.check_for_delay("PUT", "/anything")
- self.assertEqual(delay, None)
-
- def test_delay_PUT(self):
- """
- Ensure the 11th PUT will result in a delay of 6.0 seconds until
- the next request will be granced.
- """
- expected = [None] * 10 + [6.0]
- results = list(self._check(11, "PUT", "/anything"))
-
- self.assertEqual(expected, results)
-
- def test_delay_POST(self):
- """
- Ensure the 8th POST will result in a delay of 6.0 seconds until
- the next request will be granced.
- """
- expected = [None] * 7
- results = list(self._check(7, "POST", "/anything"))
- self.assertEqual(expected, results)
-
- expected = 60.0 / 7.0
- results = self._check_sum(1, "POST", "/anything")
- self.failUnlessAlmostEqual(expected, results, 8)
-
- def test_delay_GET(self):
- """
- Ensure the 11th GET will result in NO delay.
- """
- expected = [None] * 11
- results = list(self._check(11, "GET", "/anything"))
-
- self.assertEqual(expected, results)
-
- def test_delay_PUT_servers(self):
- """
- Ensure PUT on /servers limits at 5 requests, and PUT elsewhere is still
- OK after 5 requests...but then after 11 total requests, PUT limiting
- kicks in.
- """
- # First 6 requests on PUT /servers
- expected = [None] * 5 + [12.0]
- results = list(self._check(6, "PUT", "/servers"))
- self.assertEqual(expected, results)
-
- # Next 5 request on PUT /anything
- expected = [None] * 4 + [6.0]
- results = list(self._check(5, "PUT", "/anything"))
- self.assertEqual(expected, results)
-
- def test_delay_PUT_wait(self):
- """
- Ensure after hitting the limit and then waiting for the correct
- amount of time, the limit will be lifted.
- """
- expected = [None] * 10 + [6.0]
- results = list(self._check(11, "PUT", "/anything"))
- self.assertEqual(expected, results)
-
- # Advance time
- self.time += 6.0
-
- expected = [None, 6.0]
- results = list(self._check(2, "PUT", "/anything"))
- self.assertEqual(expected, results)
-
- def test_multiple_delays(self):
- """
- Ensure multiple requests still get a delay.
- """
- expected = [None] * 10 + [6.0] * 10
- results = list(self._check(20, "PUT", "/anything"))
- self.assertEqual(expected, results)
-
- self.time += 1.0
-
- expected = [5.0] * 10
- results = list(self._check(10, "PUT", "/anything"))
- self.assertEqual(expected, results)
-
- def test_multiple_users(self):
- """
- Tests involving multiple users.
- """
- # User1
- expected = [None] * 10 + [6.0] * 10
- results = list(self._check(20, "PUT", "/anything", "user1"))
- self.assertEqual(expected, results)
-
- # User2
- expected = [None] * 10 + [6.0] * 5
- results = list(self._check(15, "PUT", "/anything", "user2"))
- self.assertEqual(expected, results)
-
- self.time += 1.0
-
- # User1 again
- expected = [5.0] * 10
- results = list(self._check(10, "PUT", "/anything", "user1"))
- self.assertEqual(expected, results)
-
- self.time += 1.0
-
- # User1 again
- expected = [4.0] * 5
- results = list(self._check(5, "PUT", "/anything", "user2"))
- self.assertEqual(expected, results)
-
-
-class WsgiLimiterTest(test.TestCase):
- """
- Tests for `limits.WsgiLimiter` class.
- """
-
- def setUp(self):
- """Run before each test."""
- test.TestCase.setUp(self)
- self.time = 0.0
- self.app = limits.WsgiLimiter(TEST_LIMITS)
- self.app._limiter._get_time = self._get_time
-
- def _get_time(self):
- """Return the "time" according to this test suite."""
- return self.time
-
- def _request_data(self, verb, path):
- """Get data decribing a limit request verb/path."""
- return json.dumps({"verb": verb, "path": path})
-
- def _request(self, verb, url, username=None):
- """Make sure that POSTing to the given url causes the given username
- to perform the given action. Make the internal rate limiter return
- delay and make sure that the WSGI app returns the correct response.
- """
- if username:
- request = webob.Request.blank("/%s" % username)
- else:
- request = webob.Request.blank("/")
-
- request.method = "POST"
- request.body = self._request_data(verb, url)
- response = request.get_response(self.app)
-
- if "X-Wait-Seconds" in response.headers:
- self.assertEqual(response.status_int, 403)
- return response.headers["X-Wait-Seconds"]
-
- self.assertEqual(response.status_int, 204)
-
- def test_invalid_methods(self):
- """Only POSTs should work."""
- requests = []
- for method in ["GET", "PUT", "DELETE", "HEAD", "OPTIONS"]:
- request = webob.Request.blank("/")
- request.body = self._request_data("GET", "/something")
- response = request.get_response(self.app)
- self.assertEqual(response.status_int, 405)
-
- def test_good_url(self):
- delay = self._request("GET", "/something")
- self.assertEqual(delay, None)
-
- def test_escaping(self):
- delay = self._request("GET", "/something/jump%20up")
- self.assertEqual(delay, None)
-
- def test_response_to_delays(self):
- delay = self._request("GET", "/delayed")
- self.assertEqual(delay, None)
-
- delay = self._request("GET", "/delayed")
- self.assertEqual(delay, '60.00')
-
- def test_response_to_delays_usernames(self):
- delay = self._request("GET", "/delayed", "user1")
- self.assertEqual(delay, None)
-
- delay = self._request("GET", "/delayed", "user2")
- self.assertEqual(delay, None)
-
- delay = self._request("GET", "/delayed", "user1")
- self.assertEqual(delay, '60.00')
-
- delay = self._request("GET", "/delayed", "user2")
- self.assertEqual(delay, '60.00')
-
-
-class FakeHttplibSocket(object):
- """
- Fake `httplib.HTTPResponse` replacement.
- """
-
- def __init__(self, response_string):
- """Initialize new `FakeHttplibSocket`."""
- self._buffer = StringIO.StringIO(response_string)
-
- def makefile(self, _mode, _other):
- """Returns the socket's internal buffer."""
- return self._buffer
-
-
-class FakeHttplibConnection(object):
- """
- Fake `httplib.HTTPConnection`.
- """
-
- def __init__(self, app, host):
- """
- Initialize `FakeHttplibConnection`.
- """
- self.app = app
- self.host = host
-
- def request(self, method, path, body="", headers={}):
- """
- Requests made via this connection actually get translated and routed
- into our WSGI app, we then wait for the response and turn it back into
- an `httplib.HTTPResponse`.
- """
- req = webob.Request.blank(path)
- req.method = method
- req.headers = headers
- req.host = self.host
- req.body = body
-
- resp = str(req.get_response(self.app))
- resp = "HTTP/1.0 %s" % resp
- sock = FakeHttplibSocket(resp)
- self.http_response = httplib.HTTPResponse(sock)
- self.http_response.begin()
-
- def getresponse(self):
- """Return our generated response from the request."""
- return self.http_response
-
-
-def wire_HTTPConnection_to_WSGI(host, app):
- """Monkeypatches HTTPConnection so that if you try to connect to host, you
- are instead routed straight to the given WSGI app.
-
- After calling this method, when any code calls
-
- httplib.HTTPConnection(host)
-
- the connection object will be a fake. Its requests will be sent directly
- to the given WSGI app rather than through a socket.
-
- Code connecting to hosts other than host will not be affected.
-
- This method may be called multiple times to map different hosts to
- different apps.
- """
- class HTTPConnectionDecorator(object):
- """Wraps the real HTTPConnection class so that when you instantiate
- the class you might instead get a fake instance."""
-
- def __init__(self, wrapped):
- self.wrapped = wrapped
-
- def __call__(self, connection_host, *args, **kwargs):
- if connection_host == host:
- return FakeHttplibConnection(app, host)
- else:
- return self.wrapped(connection_host, *args, **kwargs)
-
- httplib.HTTPConnection = HTTPConnectionDecorator(httplib.HTTPConnection)
-
-
-class WsgiLimiterProxyTest(test.TestCase):
- """
- Tests for the `limits.WsgiLimiterProxy` class.
- """
-
- def setUp(self):
- """
- Do some nifty HTTP/WSGI magic which allows for WSGI to be called
- directly by something like the `httplib` library.
- """
- test.TestCase.setUp(self)
- self.time = 0.0
- self.app = limits.WsgiLimiter(TEST_LIMITS)
- self.app._limiter._get_time = self._get_time
- wire_HTTPConnection_to_WSGI("169.254.0.1:80", self.app)
- self.proxy = limits.WsgiLimiterProxy("169.254.0.1:80")
-
- def _get_time(self):
- """Return the "time" according to this test suite."""
- return self.time
-
- def test_200(self):
- """Successful request test."""
- delay = self.proxy.check_for_delay("GET", "/anything")
- self.assertEqual(delay, None)
-
- def test_403(self):
- """Forbidden request test."""
- delay = self.proxy.check_for_delay("GET", "/delayed")
- self.assertEqual(delay, None)
-
- delay = self.proxy.check_for_delay("GET", "/delayed")
- self.assertEqual(delay, '60.00')
diff --git a/nova/wsgi.py b/nova/wsgi.py
index ba0819466..21aabd556 100644
--- a/nova/wsgi.py
+++ b/nova/wsgi.py
@@ -482,6 +482,7 @@ class Serializer(object):
def _to_xml_node(self, doc, metadata, nodename, data):
"""Recursive method to convert data members to XML nodes."""
+ print "to_xml_node(%s, %s, %s, %s)" % (doc, metadata, nodename, data)
result = doc.createElement(nodename)
if type(data) is list:
singular = metadata.get('plurals', {}).get(nodename, None)
--
cgit
From 5ba3e21875d3cf3b71082477311902891706eee4 Mon Sep 17 00:00:00 2001
From: Brian Lamar
Date: Tue, 15 Mar 2011 21:09:26 -0400
Subject: Removed VIM specific stuff and changed copyright from 2010 to 2011.
---
nova/api/openstack/limits.py | 4 +---
nova/tests/api/openstack/test_limits.py | 4 +---
2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py
index 57e6bfcc2..3ecd46377 100644
--- a/nova/api/openstack/limits.py
+++ b/nova/api/openstack/limits.py
@@ -1,6 +1,4 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
+# Copyright 2011 OpenStack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py
index cf4389c1d..40178e671 100644
--- a/nova/tests/api/openstack/test_limits.py
+++ b/nova/tests/api/openstack/test_limits.py
@@ -1,6 +1,4 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
+# Copyright 2011 OpenStack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
--
cgit
From 60c7ce60826becb1ebe7f75a0a0d28b2893d70c0 Mon Sep 17 00:00:00 2001
From: Ken Pepple
Date: Tue, 15 Mar 2011 18:54:51 -0700
Subject: revised per code review
---
nova/image/local.py | 11 +++++++----
nova/tests/api/openstack/test_images.py | 9 +++++++--
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/nova/image/local.py b/nova/image/local.py
index ef92a35b5..c304a2212 100644
--- a/nova/image/local.py
+++ b/nova/image/local.py
@@ -51,12 +51,15 @@ class LocalImageService(service.BaseImageService):
def _ids(self):
"""The list of all image ids."""
images = []
- for i in os.listdir(self._path):
+ for image_dir in os.listdir(self._path):
try:
- images.append(int(i, 16))
+ images.append(int(image_dir, 16))
+ except ValueError:
+ LOG.error(
+ _("%s is not in correct directory naming format"\
+ % image_dir))
except:
- LOG.debug(
- _("%s is not in correct directory naming format" % i))
+ raise
return images
def index(self, context):
diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py
index 2c4918117..a674ccefe 100644
--- a/nova/tests/api/openstack/test_images.py
+++ b/nova/tests/api/openstack/test_images.py
@@ -22,6 +22,7 @@ and as a WSGI layer
import json
import datetime
+import os
import shutil
import tempfile
@@ -155,8 +156,12 @@ class LocalImageServiceTest(test.TestCase,
# create some old-style image directories (starting with 'ami-')
for x in [1, 2, 3]:
tempfile.mkstemp(prefix='ami-', dir=self.tempdir)
- found_images = self.service._ids()
- self.assertEqual(True, isinstance(found_images, list))
+ # create some valid image directories names
+ for x in ["1485baed", "1a60f0ee", "3123a73d"]:
+ os.makedirs(os.path.join(self.tempdir, x))
+ found_image_ids = self.service._ids()
+ self.assertEqual(True, isinstance(found_image_ids, list))
+ self.assertEqual(3, len(found_image_ids), len(found_image_ids))
class GlanceImageServiceTest(test.TestCase,
--
cgit
From be9a218e2e4b01fe19722fb0073731d8ae6a7eea Mon Sep 17 00:00:00 2001
From: Brian Lamar
Date: Tue, 15 Mar 2011 23:13:05 -0400
Subject: Added tests back for RateLimitingMiddleware which now throw correctly
serialized errors with correct error codes.
Removed some error printing, and simplified some other parts of the code with
suggestions from teammates.
---
nova/api/openstack/faults.py | 22 +++-
nova/api/openstack/limits.py | 25 ++---
nova/tests/api/openstack/test_limits.py | 172 ++++++++++++++++++++++----------
nova/wsgi.py | 1 -
4 files changed, 148 insertions(+), 72 deletions(-)
diff --git a/nova/api/openstack/faults.py b/nova/api/openstack/faults.py
index 6ed9322de..d05c61fc7 100644
--- a/nova/api/openstack/faults.py
+++ b/nova/api/openstack/faults.py
@@ -68,17 +68,31 @@ class OverLimitFault(webob.exc.HTTPException):
Rate-limited request response.
"""
- wrapped_exc = webob.exc.HTTPForbidden()
+ _serialization_metadata = {
+ "application/xml": {
+ "attributes": {
+ "overLimitFault": "code"
+ }
+ }
+ }
def __init__(self, message, details, retry_time):
"""
Initialize new `OverLimitFault` with relevant information.
"""
- self.message = message
- self.details = details
- self.retry_time = retry_time
+ self.wrapped_exc = webob.exc.HTTPForbidden()
+ self.content = {
+ "overLimitFault": {
+ "code": self.wrapped_exc.status_int,
+ "message": message,
+ "details": details,
+ },
+ }
@webob.dec.wsgify(RequestClass=wsgi.Request)
def __call__(self, request):
"""Currently just return the wrapped exception."""
+ serializer = wsgi.Serializer(self._serialization_metadata)
+ content_type = request.best_match_content_type()
+ self.wrapped_exc.body = serializer.serialize(self.content, content_type)
return self.wrapped_exc
diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py
index 3ecd46377..c4e04e9d9 100644
--- a/nova/api/openstack/limits.py
+++ b/nova/api/openstack/limits.py
@@ -54,8 +54,8 @@ class LimitsController(Controller):
"limit": ["verb", "URI", "regex", "value", "unit",
"resetTime", "remaining", "name"],
},
- "plurals" : {
- "rate" : "limit",
+ "plurals": {
+ "rate": "limit",
},
},
}
@@ -215,7 +215,12 @@ class RateLimitingMiddleware(Middleware):
"""
verb = req.method
url = req.url
- username = req.environ["nova.context"].user_id
+ context = req.environ.get("nova.context")
+
+ if context:
+ username = context.user_id
+ else:
+ username = None
delay, error = self._limiter.check_for_delay(verb, url, username)
@@ -255,14 +260,12 @@ class Limiter(object):
@return: Tuple of delay (in seconds) and error message (or None, None)
"""
- def _get_delay_list():
- """Yield limit delays."""
- for limit in self.levels[username]:
- delay = limit(verb, url)
- if delay:
- yield delay, limit.error_message
+ delays = []
- delays = list(_get_delay_list())
+ for limit in self.levels[username]:
+ delay = limit(verb, url)
+ if delay:
+ delays.append((delay, limit.error_message))
if delays:
delays.sort()
@@ -349,8 +352,6 @@ class WsgiLimiterProxy(object):
resp = conn.getresponse()
- print resp
-
if 200 >= resp.status < 300:
return None, None
diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py
index 40178e671..d1db93a59 100644
--- a/nova/tests/api/openstack/test_limits.py
+++ b/nova/tests/api/openstack/test_limits.py
@@ -22,11 +22,11 @@ import json
import StringIO
import stubout
import time
+import unittest
import webob
from xml.dom.minidom import parseString
-from nova import test
from nova.api.openstack import limits
from nova.api.openstack.limits import Limit
@@ -40,28 +40,34 @@ TEST_LIMITS = [
]
-class LimitsControllerTest(test.TestCase):
- """
- Tests for `limits.LimitsController` class.
- """
+class BaseLimitTestSuite(unittest.TestCase):
+ """Base test suite which provides relevant stubs and time abstraction."""
def setUp(self):
"""Run before each test."""
- test.TestCase.setUp(self)
self.time = 0.0
self.stubs = stubout.StubOutForTesting()
self.stubs.Set(limits.Limit, "_get_time", self._get_time)
- self.controller = limits.LimitsController()
def tearDown(self):
"""Run after each test."""
self.stubs.UnsetAll()
- test.TestCase.tearDown(self)
def _get_time(self):
"""Return the "time" according to this test suite."""
return self.time
+
+class LimitsControllerTest(BaseLimitTestSuite):
+ """
+ Tests for `limits.LimitsController` class.
+ """
+
+ def setUp(self):
+ """Run before each test."""
+ BaseLimitTestSuite.setUp(self)
+ self.controller = limits.LimitsController()
+
def _get_index_request(self, accept_header="application/json"):
"""Helper to set routing arguments."""
request = webob.Request.blank("/")
@@ -74,11 +80,11 @@ class LimitsControllerTest(test.TestCase):
def _populate_limits(self, request):
"""Put limit info into a request."""
- limits = [
+ _limits = [
Limit("GET", "*", ".*", 10, 60).display(),
Limit("POST", "*", ".*", 5, 60 * 60).display(),
]
- request.environ["nova.limits"] = limits
+ request.environ["nova.limits"] = _limits
return request
def test_empty_index_json(self):
@@ -131,7 +137,7 @@ class LimitsControllerTest(test.TestCase):
response = request.get_response(self.controller)
expected = ""
- body = response.body.replace("\n","").replace(" ", "")
+ body = response.body.replace("\n", "").replace(" ", "")
self.assertEqual(expected, body)
@@ -144,7 +150,7 @@ class LimitsControllerTest(test.TestCase):
expected = parseString("""
-
@@ -157,28 +163,108 @@ class LimitsControllerTest(test.TestCase):
self.assertEqual(expected.toxml(), body.toxml())
-class LimiterTest(test.TestCase):
+class LimitMiddlewareTest(BaseLimitTestSuite):
+ """
+ Tests for the `limits.RateLimitingMiddleware` class.
+ """
+
+ @webob.dec.wsgify
+ def _empty_app(self, request):
+ """Do-nothing WSGI app."""
+ pass
+
+ def setUp(self):
+ """Prepare middleware for use through fake WSGI app."""
+ BaseLimitTestSuite.setUp(self)
+ _limits = [
+ Limit("GET", "*", ".*", 1, 60),
+ ]
+ self.app = limits.RateLimitingMiddleware(self._empty_app, _limits)
+
+ def test_good_request(self):
+ """Test successful GET request through middleware."""
+ request = webob.Request.blank("/")
+ response = request.get_response(self.app)
+ self.assertEqual(200, response.status_int)
+
+ def test_limited_request_json(self):
+ """Test a rate-limited (403) GET request through middleware."""
+ request = webob.Request.blank("/")
+ response = request.get_response(self.app)
+ self.assertEqual(200, response.status_int)
+
+ request = webob.Request.blank("/")
+ response = request.get_response(self.app)
+ self.assertEqual(response.status_int, 403)
+
+ body = json.loads(response.body)
+ expected = "Only 1 GET request(s) can be made to * every minute."
+ value = body["overLimitFault"]["details"].strip()
+ self.assertEqual(value, expected)
+
+ def test_limited_request_xml(self):
+ """Test a rate-limited (403) response as XML"""
+ request = webob.Request.blank("/")
+ response = request.get_response(self.app)
+ self.assertEqual(200, response.status_int)
+
+ request = webob.Request.blank("/")
+ request.accept = "application/xml"
+ response = request.get_response(self.app)
+ self.assertEqual(response.status_int, 403)
+
+ root = parseString(response.body).childNodes[0]
+ expected = "Only 1 GET request(s) can be made to * every minute."
+
+ details = root.getElementsByTagName("details")
+ self.assertEqual(details.length, 1)
+
+ value = details.item(0).firstChild.data.strip()
+ self.assertEqual(value, expected)
+
+
+class LimitTest(BaseLimitTestSuite):
+ """
+ Tests for the `limits.Limit` class.
+ """
+
+ def test_GET_no_delay(self):
+ """Test a limit handles 1 GET per second."""
+ limit = Limit("GET", "*", ".*", 1, 1)
+ delay = limit("GET", "/anything")
+ self.assertEqual(None, delay)
+ self.assertEqual(0, limit.next_request)
+ self.assertEqual(0, limit.last_request)
+
+ def test_GET_delay(self):
+ """Test two calls to 1 GET per second limit."""
+ limit = Limit("GET", "*", ".*", 1, 1)
+ delay = limit("GET", "/anything")
+ self.assertEqual(None, delay)
+
+ delay = limit("GET", "/anything")
+ self.assertEqual(1, delay)
+ self.assertEqual(1, limit.next_request)
+ self.assertEqual(0, limit.last_request)
+
+ self.time += 4
+
+ delay = limit("GET", "/anything")
+ self.assertEqual(None, delay)
+ self.assertEqual(4, limit.next_request)
+ self.assertEqual(4, limit.last_request)
+
+
+class LimiterTest(BaseLimitTestSuite):
"""
Tests for the in-memory `limits.Limiter` class.
"""
def setUp(self):
"""Run before each test."""
- test.TestCase.setUp(self)
- self.time = 0.0
- self.stubs = stubout.StubOutForTesting()
- self.stubs.Set(limits.Limit, "_get_time", self._get_time)
+ BaseLimitTestSuite.setUp(self)
self.limiter = limits.Limiter(TEST_LIMITS)
- def tearDown(self):
- """Run after each test."""
- self.stubs.UnsetAll()
- test.TestCase.tearDown(self)
-
- def _get_time(self):
- """Return the "time" according to this test suite."""
- return self.time
-
def _check(self, num, verb, url, username=None):
"""Check and yield results from checks."""
for x in xrange(num):
@@ -311,28 +397,16 @@ class LimiterTest(test.TestCase):
self.assertEqual(expected, results)
-class WsgiLimiterTest(test.TestCase):
+class WsgiLimiterTest(BaseLimitTestSuite):
"""
Tests for `limits.WsgiLimiter` class.
"""
def setUp(self):
"""Run before each test."""
- test.TestCase.setUp(self)
- self.time = 0.0
- self.stubs = stubout.StubOutForTesting()
- self.stubs.Set(limits.Limit, "_get_time", self._get_time)
+ BaseLimitTestSuite.setUp(self)
self.app = limits.WsgiLimiter(TEST_LIMITS)
- def tearDown(self):
- """Run after each test."""
- self.stubs.UnsetAll()
- test.TestCase.tearDown(self)
-
- def _get_time(self):
- """Return the "time" according to this test suite."""
- return self.time
-
def _request_data(self, verb, path):
"""Get data decribing a limit request verb/path."""
return json.dumps({"verb": verb, "path": path})
@@ -476,7 +550,7 @@ def wire_HTTPConnection_to_WSGI(host, app):
httplib.HTTPConnection = HTTPConnectionDecorator(httplib.HTTPConnection)
-class WsgiLimiterProxyTest(test.TestCase):
+class WsgiLimiterProxyTest(BaseLimitTestSuite):
"""
Tests for the `limits.WsgiLimiterProxy` class.
"""
@@ -486,23 +560,11 @@ class WsgiLimiterProxyTest(test.TestCase):
Do some nifty HTTP/WSGI magic which allows for WSGI to be called
directly by something like the `httplib` library.
"""
- test.TestCase.setUp(self)
- self.time = 0.0
- self.stubs = stubout.StubOutForTesting()
- self.stubs.Set(limits.Limit, "_get_time", self._get_time)
+ BaseLimitTestSuite.setUp(self)
self.app = limits.WsgiLimiter(TEST_LIMITS)
wire_HTTPConnection_to_WSGI("169.254.0.1:80", self.app)
self.proxy = limits.WsgiLimiterProxy("169.254.0.1:80")
- def tearDown(self):
- """Run after each test."""
- self.stubs.UnsetAll()
- test.TestCase.tearDown(self)
-
- def _get_time(self):
- """Return the "time" according to this test suite."""
- return self.time
-
def test_200(self):
"""Successful request test."""
delay = self.proxy.check_for_delay("GET", "/anything")
@@ -519,4 +581,4 @@ class WsgiLimiterProxyTest(test.TestCase):
expected = ("60.00", "403 Forbidden\n\nOnly 1 GET request(s) can be "\
"made to /delayed every minute.")
- self.assertEqual((delay, error), expected)
+ self.assertEqual((delay, error), expected)
diff --git a/nova/wsgi.py b/nova/wsgi.py
index 21aabd556..ba0819466 100644
--- a/nova/wsgi.py
+++ b/nova/wsgi.py
@@ -482,7 +482,6 @@ class Serializer(object):
def _to_xml_node(self, doc, metadata, nodename, data):
"""Recursive method to convert data members to XML nodes."""
- print "to_xml_node(%s, %s, %s, %s)" % (doc, metadata, nodename, data)
result = doc.createElement(nodename)
if type(data) is list:
singular = metadata.get('plurals', {}).get(nodename, None)
--
cgit
From 659cb8bd43e2091c61f44dacf21274a677ea3146 Mon Sep 17 00:00:00 2001
From: Brian Waldon
Date: Tue, 15 Mar 2011 23:35:44 -0400
Subject: openstack api 1.0 flavors resource now implemented; adding flavors
request value testing
---
nova/api/openstack/flavors.py | 12 ++++--
nova/tests/api/openstack/test_flavors.py | 71 +++++++++++++++++++++++++++++++-
2 files changed, 78 insertions(+), 5 deletions(-)
diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py
index f3d040ba3..c99b945fb 100644
--- a/nova/api/openstack/flavors.py
+++ b/nova/api/openstack/flavors.py
@@ -22,6 +22,7 @@ from nova import context
from nova.api.openstack import faults
from nova.api.openstack import common
from nova.compute import instance_types
+from nova.api.openstack.views import flavors as flavors_views
from nova import wsgi
import nova.api.openstack
@@ -47,13 +48,18 @@ class Controller(wsgi.Controller):
def show(self, req, id):
"""Return data about the given flavor id."""
ctxt = req.environ['nova.context']
- values = db.instance_type_get_by_flavor_id(ctxt, id)
+ flavor = db.api.instance_type_get_by_flavor_id(ctxt, id)
+ values = {
+ "id": flavor["flavorid"],
+ "name": flavor["name"],
+ "ram": flavor["memory_mb"],
+ "disk": flavor["local_gb"],
+ }
return dict(flavor=values)
- raise faults.Fault(exc.HTTPNotFound())
def _all_ids(self, req):
"""Return the list of all flavorids."""
ctxt = req.environ['nova.context']
- inst_types = db.instance_type_get_all(ctxt)
+ inst_types = db.api.instance_type_get_all(ctxt)
flavor_ids = [inst_types[i]['flavorid'] for i in inst_types.keys()]
return sorted(flavor_ids)
diff --git a/nova/tests/api/openstack/test_flavors.py b/nova/tests/api/openstack/test_flavors.py
index 8280a505f..8f53d14cc 100644
--- a/nova/tests/api/openstack/test_flavors.py
+++ b/nova/tests/api/openstack/test_flavors.py
@@ -15,17 +15,38 @@
# License for the specific language governing permissions and limitations
# under the License.
+import json
import stubout
import webob
from nova import test
import nova.api
from nova import context
-from nova import db
from nova.api.openstack import flavors
+from nova import db
from nova.tests.api.openstack import fakes
+def stub_flavor(flavorid, name, memory_mb="256", local_gb="10"):
+ return {
+ "flavorid": str(flavorid),
+ "name": name,
+ "memory_mb": memory_mb,
+ "local_gb": local_gb,
+ }
+
+
+def return_instance_type_by_flavor_id(context, flavorid):
+ return stub_flavor(flavorid, "flavor %s" % (flavorid,))
+
+def return_instance_types(context, num=2):
+ instance_types = {}
+ for i in xrange(1,num+1):
+ name = "flavor %s" % (i,)
+ instance_types[name] = stub_flavor(i, name)
+ return instance_types
+
+
class FlavorsTest(test.TestCase):
def setUp(self):
super(FlavorsTest, self).setUp()
@@ -35,6 +56,10 @@ class FlavorsTest(test.TestCase):
fakes.stub_out_networking(self.stubs)
fakes.stub_out_rate_limiting(self.stubs)
fakes.stub_out_auth(self.stubs)
+ self.stubs.Set(nova.db.api, "instance_type_get_all",
+ return_instance_types)
+ self.stubs.Set(nova.db.api, "instance_type_get_by_flavor_id",
+ return_instance_type_by_flavor_id)
self.context = context.get_admin_context()
def tearDown(self):
@@ -45,8 +70,50 @@ class FlavorsTest(test.TestCase):
req = webob.Request.blank('/v1.0/flavors')
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200)
+ flavors = json.loads(res.body)["flavors"]
+ expected = [
+ {
+ "id": "1",
+ "name": "flavor 1",
+ },
+ {
+ "id": "2",
+ "name": "flavor 2",
+ },
+ ]
+ self.assertEqual(flavors, expected)
+
+ def test_get_flavor_list_detail(self):
+ req = webob.Request.blank('/v1.0/flavors/detail')
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ flavors = json.loads(res.body)["flavors"]
+ expected = [
+ {
+ "id": "1",
+ "name": "flavor 1",
+ "ram": "256",
+ "disk": "10",
+ },
+ {
+ "id": "2",
+ "name": "flavor 2",
+ "ram": "256",
+ "disk": "10",
+ },
+ ]
+ self.assertEqual(flavors, expected)
+
def test_get_flavor_by_id(self):
- req = webob.Request.blank('/v1.0/flavors/1')
+ req = webob.Request.blank('/v1.0/flavors/12')
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200)
+ flavor = json.loads(res.body)["flavor"]
+ expected = {
+ "id": "12",
+ "name": "flavor 12",
+ "ram": "256",
+ "disk": "10",
+ }
+ self.assertEqual(flavor, expected)
--
cgit
From 33419a2f84ea6bfbf6ff47fb1f01ef0c21389a54 Mon Sep 17 00:00:00 2001
From: Brian Waldon
Date: Wed, 16 Mar 2011 00:22:34 -0400
Subject: pep8 fixes
---
nova/tests/api/openstack/test_flavors.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/nova/tests/api/openstack/test_flavors.py b/nova/tests/api/openstack/test_flavors.py
index 8f53d14cc..4f504808c 100644
--- a/nova/tests/api/openstack/test_flavors.py
+++ b/nova/tests/api/openstack/test_flavors.py
@@ -39,9 +39,10 @@ def stub_flavor(flavorid, name, memory_mb="256", local_gb="10"):
def return_instance_type_by_flavor_id(context, flavorid):
return stub_flavor(flavorid, "flavor %s" % (flavorid,))
+
def return_instance_types(context, num=2):
instance_types = {}
- for i in xrange(1,num+1):
+ for i in xrange(1, num + 1):
name = "flavor %s" % (i,)
instance_types[name] = stub_flavor(i, name)
return instance_types
@@ -103,7 +104,6 @@ class FlavorsTest(test.TestCase):
},
]
self.assertEqual(flavors, expected)
-
def test_get_flavor_by_id(self):
req = webob.Request.blank('/v1.0/flavors/12')
--
cgit
From 20031162372329b40ca90b1bc39cebb4f187cace Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Tue, 15 Mar 2011 23:22:17 -0700
Subject: Use integer ids for (fake) users
---
nova/tests/api/openstack/fakes.py | 3 +--
nova/tests/api/openstack/test_accounts.py | 4 ++--
nova/tests/api/openstack/test_users.py | 4 ++--
3 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py
index 52ac80e3f..c2ae48ce4 100644
--- a/nova/tests/api/openstack/fakes.py
+++ b/nova/tests/api/openstack/fakes.py
@@ -240,8 +240,7 @@ class FakeAuthManager(object):
@classmethod
def reset_fake_data(cls):
- cls.auth_data = dict(acc1=User('guy1', 'guy1', 'acc1',
- 'fortytwo!', False))
+ cls.auth_data = dict(acc1=User(1, 'guy1', 'acc1', 'fortytwo!', False))
cls.projects = dict(testacct=Project('testacct',
'testacct',
'guy1',
diff --git a/nova/tests/api/openstack/test_accounts.py b/nova/tests/api/openstack/test_accounts.py
index 1bf49b33b..5cb08ffd2 100644
--- a/nova/tests/api/openstack/test_accounts.py
+++ b/nova/tests/api/openstack/test_accounts.py
@@ -57,8 +57,8 @@ class AccountsTest(test.TestCase):
self.allow_admin = FLAGS.allow_admin_api
FLAGS.allow_admin_api = True
fakemgr = fakes.FakeAuthManager()
- joeuser = User('guy1', 'guy1', 'acc1', 'fortytwo!', False)
- superuser = User('guy2', 'guy2', 'acc2', 'swordfish', True)
+ joeuser = User(1, 'guy1', 'acc1', 'fortytwo!', False)
+ superuser = User(2, 'guy2', 'acc2', 'swordfish', True)
fakemgr.add_user(joeuser)
fakemgr.add_user(superuser)
fakemgr.create_project('test1', joeuser)
diff --git a/nova/tests/api/openstack/test_users.py b/nova/tests/api/openstack/test_users.py
index a62db7efc..652aac936 100644
--- a/nova/tests/api/openstack/test_users.py
+++ b/nova/tests/api/openstack/test_users.py
@@ -61,8 +61,8 @@ class UsersTest(test.TestCase):
self.allow_admin = FLAGS.allow_admin_api
FLAGS.allow_admin_api = True
fakemgr = fakes.FakeAuthManager()
- fakemgr.add_user(User('guy1', 'guy1', 'acc1', 'fortytwo!', False))
- fakemgr.add_user(User('guy2', 'guy2', 'acc2', 'swordfish', True))
+ fakemgr.add_user(User(1, 'guy1', 'acc1', 'fortytwo!', False))
+ fakemgr.add_user(User(2, 'guy2', 'acc2', 'swordfish', True))
def tearDown(self):
self.stubs.UnsetAll()
--
cgit
From e2f8c143eab3b43acd9e3658a480f75f435e7d42 Mon Sep 17 00:00:00 2001
From: Koji Iida
Date: Wed, 16 Mar 2011 19:51:06 +0900
Subject: Updating gateway_v6 in _on_set_network_host() is not required for
FlatManager
---
nova/network/manager.py | 5 -----
1 file changed, 5 deletions(-)
diff --git a/nova/network/manager.py b/nova/network/manager.py
index c51eb9ad0..7e28e6da2 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -404,11 +404,6 @@ class FlatManager(NetworkManager):
net = {}
net['injected'] = FLAGS.flat_injected
net['dns'] = FLAGS.flat_network_dns
- if not FLAGS.fake_network:
- if(FLAGS.use_ipv6):
- net['gateway_v6'] = \
- utils.get_my_linklocal(
- FLAGS.flat_network_bridge)
self.db.network_update(context, network_id, net)
def allocate_floating_ip(self, context, project_id):
--
cgit
From 8964cbecc10885bc6eff08544d62db1747fb14ef Mon Sep 17 00:00:00 2001
From: Koji Iida
Date: Wed, 16 Mar 2011 20:24:20 +0900
Subject: pep8 clean
---
nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
index be1edc8f6..9f98f436f 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
@@ -83,8 +83,7 @@ networks = Table('networks', meta,
Column(
'label',
String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False))
- )
+ unicode_error=None, _warn_on_bytestring=False)))
fixed_ips = Table('fixed_ips', meta,
Column('created_at', DateTime(timezone=False)),
--
cgit
From 2e81ce6bb5b1083220e7ae5c17113fd44465ddbf Mon Sep 17 00:00:00 2001
From: Koji Iida
Date: Wed, 16 Mar 2011 21:17:19 +0900
Subject: Fix instance creation fail under use_ipv6=false and FlatManager
---
nova/virt/libvirt_conn.py | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index 9efbb3342..a850bad87 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -660,11 +660,10 @@ class LibvirtConnection(object):
if network_ref['injected']:
admin_context = context.get_admin_context()
address = db.instance_get_fixed_address(admin_context, inst['id'])
- address_v6 = db.instance_get_fixed_address_v6(admin_context,
- inst['id'])
- gateway_v6 = network_ref['gateway_v6']
- if not gateway_v6:
- gateway_v6 = "fd00::"
+ address_v6 = None
+ if FLAGS.use_ipv6:
+ address_v6 = db.instance_get_fixed_address_v6(admin_context,
+ inst['id'])
interfaces_info = {'address': address,
'netmask': network_ref['netmask'],
--
cgit
From a586714557e38116b6b4f473aa21ac54ff0223e7 Mon Sep 17 00:00:00 2001
From: Brian Lamar
Date: Wed, 16 Mar 2011 10:10:58 -0400
Subject: Added i18n to error message.
---
nova/api/openstack/limits.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py
index c4e04e9d9..1fe519f8a 100644
--- a/nova/api/openstack/limits.py
+++ b/nova/api/openstack/limits.py
@@ -225,7 +225,7 @@ class RateLimitingMiddleware(Middleware):
delay, error = self._limiter.check_for_delay(verb, url, username)
if delay:
- msg = "This request was rate-limited."
+ msg = _("This request was rate-limited.")
retry = time.time() + delay
return faults.OverLimitFault(msg, error, retry)
--
cgit
From 5379f3654e04a0443f3237623f772a17f13e9d90 Mon Sep 17 00:00:00 2001
From: Trey Morris
Date: Wed, 16 Mar 2011 12:44:38 -0500
Subject: refactored, bugfixes
---
nova/virt/xenapi/vm_utils.py | 4 +-
nova/virt/xenapi/vmops.py | 163 +++++++++++++++++++------------------------
2 files changed, 72 insertions(+), 95 deletions(-)
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index f07b57796..1f03b4124 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -234,11 +234,11 @@ class VMHelper(HelperBase):
raise StorageError(_('Unable to destroy VBD %s') % vbd_ref)
@classmethod
- def create_vif(cls, session, vm_ref, network_ref, mac_address, dev="0"):
+ def create_vif(cls, session, vm_ref, network_ref, mac_address, dev):
"""Create a VIF record. Returns a Deferred that gives the new
VIF reference."""
vif_rec = {}
- vif_rec['device'] = dev
+ vif_rec['device'] = str(dev)
vif_rec['network'] = network_ref
vif_rec['VM'] = vm_ref
vif_rec['MAC'] = mac_address
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 64f2c6231..485dd41ca 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -128,13 +128,17 @@ class VMOps(object):
vdi_ref=vdi_ref, userdevice=0, bootable=True)
# inject_network_info and create vifs
- if network_info is not None:
- self.inject_network_info(instance, network_info)
- self.create_vifs(instance, [nw for (nw, mapping) in network_info])
- else:
- # TODO(tr3buchet) - goes away with multi-nic
- networks = self.inject_network_info(instance)
- self.create_vifs(instance, networks)
+ # TODO(tr3buchet) - check to make sure we have network info, otherwise
+ # create it now. This goes away once nova-multi-nic hits.
+ if network_info is None:
+ admin_context = context.get_admin_context()
+ IPs = db.fixed_ip_get_all_by_instance(admin_context,
+ instance['id'])
+ networks = db.network_get_all_by_instance(admin_context,
+ instance['id'])
+ network_info = self._get_network_info(instance, networks, IPs)
+ self.inject_network_info(vm_ref, network_info)
+ self.create_vifs(vm_ref, network_info)
LOG.debug(_('Starting VM %s...'), vm_ref)
self._start(instance, vm_ref)
@@ -689,104 +693,77 @@ class VMOps(object):
# TODO: implement this!
return 'http://fakeajaxconsole/fake_url'
- def inject_network_info(self, instance, network_info=None):
+ # TODO(tr3buchet) - remove this function after nova multi-nic
+ def _get_network_info(self, instance, networks, IPs):
+ """creates network info list for instance"""
+
+ tuple_list = []
+ for network in networks:
+ network_IPs = [ip for ip in IPs if ip.network_id == network.id]
+
+ def ip_dict(ip):
+ return {
+ "ip": ip.address,
+ "netmask": network["netmask"],
+ "enabled": "1"}
+
+ def ip6_dict(ip6):
+ return {
+ "ip": ip6.addressV6,
+ "netmask": ip6.netmaskV6,
+ "gateway": ip6.gatewayV6,
+ "enabled": "1"}
+
+ mac_id = instance.mac_address.replace(':', '')
+ location = 'vm-data/networking/%s' % mac_id
+ info = {
+ 'label': network['label'],
+ 'gateway': network['gateway'],
+ 'mac': instance.mac_address,
+ 'dns': [network['dns']],
+ 'ips': [ip_dict(ip) for ip in network_IPs],
+ 'ip6s': [ip6_dict(ip) for ip in network_IPs]}
+ tuple_list.append((network, info))
+
+ def inject_network_info(self, vm_ref, network_info):
"""
Generate the network info and make calls to place it into the
xenstore and the xenstore param list
-
"""
- vm_ref = self._get_vm_opaque_ref(instance.id)
- logging.debug(_("injecting network info to xenstore for vm: |%s|"),
- vm_ref)
- if network_info is not None:
- for (network, mapping) in network_info:
- self.write_to_param_xenstore(vm_ref, {location: mapping})
- try:
- self.write_to_xenstore(vm_ref, location,
- mapping['location'])
- except KeyError:
- # catch KeyError for domid if instance isn't running
- pass
- else:
- # TODO(tr3buchet) - this bit here when network_info is None goes
- # away with multi-nic
- admin_context = context.get_admin_context()
- IPs = db.fixed_ip_get_all_by_instance(admin_context,
- instance['id'])
- networks = db.network_get_all_by_instance(admin_context,
- instance['id'])
- for network in networks:
- network_IPs = [ip for ip in IPs if ip.network_id == network.id]
-
- def ip_dict(ip):
- return {
- "ip": ip.address,
- "netmask": network["netmask"],
- "enabled": "1"}
-
- def ip6_dict(ip6):
- return {
- "ip": ip6.addressV6,
- "netmask": ip6.netmaskV6,
- "gateway": ip6.gatewayV6,
- "enabled": "1"}
-
- mac_id = instance.mac_address.replace(':', '')
- location = 'vm-data/networking/%s' % mac_id
- mapping = {
- 'label': network['label'],
- 'gateway': network['gateway'],
- 'mac': instance.mac_address,
- 'dns': [network['dns']],
- 'ips': [ip_dict(ip) for ip in network_IPs],
- 'ip6s': [ip6_dict(ip) for ip in network_IPs]}
-
- self.write_to_param_xenstore(vm_ref, {location: mapping})
-
- try:
- self.write_to_xenstore(vm_ref, location,
- mapping['location'])
- except KeyError:
- # catch KeyError for domid if instance isn't running
- pass
-
- return networks
-
- def create_vifs(self, instance, networks=None):
- """
- Creates vifs for an instance
+ logging.debug(_("injecting network info to xs for vm: |%s|"), vm_ref)
- """
- vm_ref = self._get_vm_opaque_ref(instance.id)
+ # make sure we have a vm opaque ref (raises otherwise)
+ self._session.get_xenapi().VM.get_record(vm_ref)
+
+ for (network, info) in network_info:
+ location = 'vm-data/networking/%s' % info['mac'].replace(':', '')
+ self.write_to_param_xenstore(vm_ref, {location: info})
+ try:
+ self.write_to_xenstore(vm_ref, location, info)
+ except KeyError:
+ # catch KeyError for domid if instance isn't running
+ pass
+
+ def create_vifs(self, vm_ref, network_info):
+ """Creates vifs for an instance"""
logging.debug(_("creating vif(s) for vm: |%s|"), vm_ref)
- # TODO(tr3buchet) - goes away with multi-nic
- if networks is None:
- networks = db.network_get_all_by_instance(admin_context,
- instance['id'])
- # TODO(tr3buchet) - remove comment in multi-nic
- # this bit here about creating the vifs will be updated
- # in multi-nic to handle multiple IPs on the same network
- # and multiple networks
- # for now it works as there is only one of each
- for network in networks:
+
+ # make sure we have a vm opaque ref (raises otherwise)
+ self._session.get_xenapi().VM.get_record(vm_ref)
+
+ device = 0
+ for (network, info) in networks:
+ mac_address = info['mac']
bridge = network['bridge']
network_ref = \
NetworkHelper.find_network_with_bridge(self._session, bridge)
- if network_ref:
- try:
- device = "1" if instance._rescue else "0"
- except AttributeError:
- device = "0"
-
- VMHelper.create_vif(self._session, vm_ref, network_ref,
- instance.mac_address, device)
+ VMHelper.create_vif(self._session, vm_ref, network_ref,
+ mac_address, device)
+ device += 1
def reset_network(self, instance):
- """
- Creates uuid arg to pass to make_agent_call and calls it.
-
- """
+ """Creates uuid arg to pass to make_agent_call and calls it."""
args = {'id': str(uuid.uuid4())}
resp = self._make_agent_call('resetnetwork', instance, '', args)
--
cgit
From d418926b514372f0f48922024e600bafcc657fd9 Mon Sep 17 00:00:00 2001
From: Trey Morris
Date: Wed, 16 Mar 2011 12:50:11 -0500
Subject: forgot to return network info - teehee
---
nova/virt/xenapi/vmops.py | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 485dd41ca..27f9a3a17 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -697,7 +697,7 @@ class VMOps(object):
def _get_network_info(self, instance, networks, IPs):
"""creates network info list for instance"""
- tuple_list = []
+ network_info = []
for network in networks:
network_IPs = [ip for ip in IPs if ip.network_id == network.id]
@@ -714,8 +714,6 @@ class VMOps(object):
"gateway": ip6.gatewayV6,
"enabled": "1"}
- mac_id = instance.mac_address.replace(':', '')
- location = 'vm-data/networking/%s' % mac_id
info = {
'label': network['label'],
'gateway': network['gateway'],
@@ -723,7 +721,8 @@ class VMOps(object):
'dns': [network['dns']],
'ips': [ip_dict(ip) for ip in network_IPs],
'ip6s': [ip6_dict(ip) for ip in network_IPs]}
- tuple_list.append((network, info))
+ network_info.append((network, info))
+ return network_info
def inject_network_info(self, vm_ref, network_info):
"""
@@ -752,7 +751,7 @@ class VMOps(object):
self._session.get_xenapi().VM.get_record(vm_ref)
device = 0
- for (network, info) in networks:
+ for (network, info) in network_info:
mac_address = info['mac']
bridge = network['bridge']
network_ref = \
--
cgit
From 7de1ef791296d547c2691454d5cb5451087cd76b Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Wed, 16 Mar 2011 12:15:57 -0700
Subject: User ids are strings, and are not necessarily == name. Also fix so
that non-existent user gives a 404, not a 500.
---
nova/api/openstack/users.py | 17 +++++++--
nova/auth/manager.py | 11 +++++-
nova/tests/api/openstack/fakes.py | 4 +--
nova/tests/api/openstack/test_accounts.py | 22 ++++++------
nova/tests/api/openstack/test_auth.py | 8 ++---
nova/tests/api/openstack/test_users.py | 58 +++++++++++++++++++++----------
6 files changed, 79 insertions(+), 41 deletions(-)
diff --git a/nova/api/openstack/users.py b/nova/api/openstack/users.py
index ebd0f4512..d3ab3d553 100644
--- a/nova/api/openstack/users.py
+++ b/nova/api/openstack/users.py
@@ -13,13 +13,14 @@
# License for the specific language governing permissions and limitations
# under the License.
-import common
+from webob import exc
from nova import exception
from nova import flags
from nova import log as logging
from nova import wsgi
-
+from nova.api.openstack import common
+from nova.api.openstack import faults
from nova.auth import manager
FLAGS = flags.FLAGS
@@ -63,7 +64,17 @@ class Controller(wsgi.Controller):
def show(self, req, id):
"""Return data about the given user id"""
- user = self.manager.get_user(id)
+
+ #NOTE(justinsb): The drivers are a little inconsistent in how they
+ # deal with "NotFound" - some throw, some return None.
+ try:
+ user = self.manager.get_user(id)
+ except exception.NotFound:
+ user = None
+
+ if user is None:
+ raise faults.Fault(exc.HTTPNotFound())
+
return dict(user=_translate_keys(user))
def delete(self, req, id):
diff --git a/nova/auth/manager.py b/nova/auth/manager.py
index 450ab803a..793499629 100644
--- a/nova/auth/manager.py
+++ b/nova/auth/manager.py
@@ -96,10 +96,19 @@ class AuthBase(object):
class User(AuthBase):
- """Object representing a user"""
+ """Object representing a user
+
+ The following attributes are defined:
+ :id: A system identifier for the user. A string (for LDAP)
+ :name: The user name, potentially in some more friendly format
+ :access: The 'username' for EC2 authentication
+ :secret: The 'password' for EC2 authenticatoin
+ :admin: ???
+ """
def __init__(self, id, name, access, secret, admin):
AuthBase.__init__(self)
+ assert isinstance(id, basestring)
self.id = id
self.name = name
self.access = access
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py
index c2ae48ce4..5decb2bad 100644
--- a/nova/tests/api/openstack/fakes.py
+++ b/nova/tests/api/openstack/fakes.py
@@ -240,10 +240,10 @@ class FakeAuthManager(object):
@classmethod
def reset_fake_data(cls):
- cls.auth_data = dict(acc1=User(1, 'guy1', 'acc1', 'fortytwo!', False))
+ cls.auth_data = dict(u1=User('id1', 'guy1', 'acc1', 'secret1', False))
cls.projects = dict(testacct=Project('testacct',
'testacct',
- 'guy1',
+ 'id1',
'test',
[]))
diff --git a/nova/tests/api/openstack/test_accounts.py b/nova/tests/api/openstack/test_accounts.py
index 5cb08ffd2..64abcf48c 100644
--- a/nova/tests/api/openstack/test_accounts.py
+++ b/nova/tests/api/openstack/test_accounts.py
@@ -19,11 +19,9 @@ import json
import stubout
import webob
-import nova.api
-import nova.api.openstack.auth
-from nova import context
from nova import flags
from nova import test
+from nova.api.openstack import accounts
from nova.auth.manager import User
from nova.tests.api.openstack import fakes
@@ -44,9 +42,9 @@ class AccountsTest(test.TestCase):
def setUp(self):
super(AccountsTest, self).setUp()
self.stubs = stubout.StubOutForTesting()
- self.stubs.Set(nova.api.openstack.accounts.Controller, '__init__',
+ self.stubs.Set(accounts.Controller, '__init__',
fake_init)
- self.stubs.Set(nova.api.openstack.accounts.Controller, '_check_admin',
+ self.stubs.Set(accounts.Controller, '_check_admin',
fake_admin_check)
fakes.FakeAuthManager.clear_fakes()
fakes.FakeAuthDatabase.data = {}
@@ -57,8 +55,8 @@ class AccountsTest(test.TestCase):
self.allow_admin = FLAGS.allow_admin_api
FLAGS.allow_admin_api = True
fakemgr = fakes.FakeAuthManager()
- joeuser = User(1, 'guy1', 'acc1', 'fortytwo!', False)
- superuser = User(2, 'guy2', 'acc2', 'swordfish', True)
+ joeuser = User('id1', 'guy1', 'acc1', 'secret1', False)
+ superuser = User('id2', 'guy2', 'acc2', 'secret2', True)
fakemgr.add_user(joeuser)
fakemgr.add_user(superuser)
fakemgr.create_project('test1', joeuser)
@@ -76,7 +74,7 @@ class AccountsTest(test.TestCase):
self.assertEqual(res_dict['account']['id'], 'test1')
self.assertEqual(res_dict['account']['name'], 'test1')
- self.assertEqual(res_dict['account']['manager'], 'guy1')
+ self.assertEqual(res_dict['account']['manager'], 'id1')
self.assertEqual(res.status_int, 200)
def test_account_delete(self):
@@ -88,7 +86,7 @@ class AccountsTest(test.TestCase):
def test_account_create(self):
body = dict(account=dict(description='test account',
- manager='guy1'))
+ manager='id1'))
req = webob.Request.blank('/v1.0/accounts/newacct')
req.headers["Content-Type"] = "application/json"
req.method = 'PUT'
@@ -101,14 +99,14 @@ class AccountsTest(test.TestCase):
self.assertEqual(res_dict['account']['id'], 'newacct')
self.assertEqual(res_dict['account']['name'], 'newacct')
self.assertEqual(res_dict['account']['description'], 'test account')
- self.assertEqual(res_dict['account']['manager'], 'guy1')
+ self.assertEqual(res_dict['account']['manager'], 'id1')
self.assertTrue('newacct' in
fakes.FakeAuthManager.projects)
self.assertEqual(len(fakes.FakeAuthManager.projects.values()), 3)
def test_account_update(self):
body = dict(account=dict(description='test account',
- manager='guy2'))
+ manager='id2'))
req = webob.Request.blank('/v1.0/accounts/test1')
req.headers["Content-Type"] = "application/json"
req.method = 'PUT'
@@ -121,5 +119,5 @@ class AccountsTest(test.TestCase):
self.assertEqual(res_dict['account']['id'], 'test1')
self.assertEqual(res_dict['account']['name'], 'test1')
self.assertEqual(res_dict['account']['description'], 'test account')
- self.assertEqual(res_dict['account']['manager'], 'guy2')
+ self.assertEqual(res_dict['account']['manager'], 'id2')
self.assertEqual(len(fakes.FakeAuthManager.projects.values()), 2)
diff --git a/nova/tests/api/openstack/test_auth.py b/nova/tests/api/openstack/test_auth.py
index e1f936bb1..446c5c149 100644
--- a/nova/tests/api/openstack/test_auth.py
+++ b/nova/tests/api/openstack/test_auth.py
@@ -51,7 +51,7 @@ class Test(test.TestCase):
def test_authorize_user(self):
f = fakes.FakeAuthManager()
- u = nova.auth.manager.User(1, 'user1', 'user1_key', None, None)
+ u = nova.auth.manager.User('id1', 'user1', 'user1_key', None, None)
f.add_user(u)
req = webob.Request.blank('/v1.0/')
@@ -66,7 +66,7 @@ class Test(test.TestCase):
def test_authorize_token(self):
f = fakes.FakeAuthManager()
- u = nova.auth.manager.User(1, 'user1', 'user1_key', None, None)
+ u = nova.auth.manager.User('id1', 'user1', 'user1_key', None, None)
f.add_user(u)
f.create_project('user1_project', u)
@@ -124,7 +124,7 @@ class Test(test.TestCase):
def test_bad_user_good_key(self):
f = fakes.FakeAuthManager()
- u = nova.auth.manager.User(1, 'user1', 'user1_key', None, None)
+ u = nova.auth.manager.User('id1', 'user1', 'user1_key', None, None)
f.add_user(u)
req = webob.Request.blank('/v1.0/')
@@ -190,7 +190,7 @@ class TestLimiter(test.TestCase):
def test_authorize_token(self):
f = fakes.FakeAuthManager()
- u = nova.auth.manager.User(1, 'user1', 'user1_key', None, None)
+ u = nova.auth.manager.User('id1', 'user1', 'user1_key', None, None)
f.add_user(u)
f.create_project('test', u)
diff --git a/nova/tests/api/openstack/test_users.py b/nova/tests/api/openstack/test_users.py
index 652aac936..effb2f592 100644
--- a/nova/tests/api/openstack/test_users.py
+++ b/nova/tests/api/openstack/test_users.py
@@ -18,11 +18,10 @@ import json
import stubout
import webob
-import nova.api
-import nova.api.openstack.auth
-from nova import context
from nova import flags
from nova import test
+from nova import utils
+from nova.api.openstack import users
from nova.auth.manager import User, Project
from nova.tests.api.openstack import fakes
@@ -43,14 +42,14 @@ class UsersTest(test.TestCase):
def setUp(self):
super(UsersTest, self).setUp()
self.stubs = stubout.StubOutForTesting()
- self.stubs.Set(nova.api.openstack.users.Controller, '__init__',
+ self.stubs.Set(users.Controller, '__init__',
fake_init)
- self.stubs.Set(nova.api.openstack.users.Controller, '_check_admin',
+ self.stubs.Set(users.Controller, '_check_admin',
fake_admin_check)
fakes.FakeAuthManager.clear_fakes()
fakes.FakeAuthManager.projects = dict(testacct=Project('testacct',
'testacct',
- 'guy1',
+ 'id1',
'test',
[]))
fakes.FakeAuthDatabase.data = {}
@@ -61,8 +60,8 @@ class UsersTest(test.TestCase):
self.allow_admin = FLAGS.allow_admin_api
FLAGS.allow_admin_api = True
fakemgr = fakes.FakeAuthManager()
- fakemgr.add_user(User(1, 'guy1', 'acc1', 'fortytwo!', False))
- fakemgr.add_user(User(2, 'guy2', 'acc2', 'swordfish', True))
+ fakemgr.add_user(User('id1', 'guy1', 'acc1', 'secret1', False))
+ fakemgr.add_user(User('id2', 'guy2', 'acc2', 'secret2', True))
def tearDown(self):
self.stubs.UnsetAll()
@@ -78,28 +77,44 @@ class UsersTest(test.TestCase):
self.assertEqual(len(res_dict['users']), 2)
def test_get_user_by_id(self):
- req = webob.Request.blank('/v1.0/users/guy2')
+ req = webob.Request.blank('/v1.0/users/id2')
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
- self.assertEqual(res_dict['user']['id'], 'guy2')
+ self.assertEqual(res_dict['user']['id'], 'id2')
self.assertEqual(res_dict['user']['name'], 'guy2')
- self.assertEqual(res_dict['user']['secret'], 'swordfish')
+ self.assertEqual(res_dict['user']['secret'], 'secret2')
self.assertEqual(res_dict['user']['admin'], True)
self.assertEqual(res.status_int, 200)
def test_user_delete(self):
- req = webob.Request.blank('/v1.0/users/guy1')
+ # Check the user exists
+ req = webob.Request.blank('/v1.0/users/id1')
+ res = req.get_response(fakes.wsgi_app())
+ res_dict = json.loads(res.body)
+
+ self.assertEqual(res_dict['user']['id'], 'id1')
+ self.assertEqual(res.status_int, 200)
+
+ # Delete the user
+ req = webob.Request.blank('/v1.0/users/id1')
req.method = 'DELETE'
res = req.get_response(fakes.wsgi_app())
- self.assertTrue('guy1' not in [u.id for u in
+ self.assertTrue('id1' not in [u.id for u in
fakes.FakeAuthManager.auth_data])
self.assertEqual(res.status_int, 200)
+ # Check the user is not returned (and returns 404)
+ req = webob.Request.blank('/v1.0/users/id1')
+ res = req.get_response(fakes.wsgi_app())
+ res_dict = json.loads(res.body)
+ self.assertEqual(res.status_int, 404)
+
def test_user_create(self):
+ secret = utils.generate_password()
body = dict(user=dict(name='test_guy',
access='acc3',
- secret='invasionIsInNormandy',
+ secret=secret,
admin=True))
req = webob.Request.blank('/v1.0/users')
req.headers["Content-Type"] = "application/json"
@@ -110,20 +125,25 @@ class UsersTest(test.TestCase):
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 200)
+
+ # NOTE(justinsb): This is a questionable assertion in general
+ # fake sets id=name, but others might not...
self.assertEqual(res_dict['user']['id'], 'test_guy')
+
self.assertEqual(res_dict['user']['name'], 'test_guy')
self.assertEqual(res_dict['user']['access'], 'acc3')
- self.assertEqual(res_dict['user']['secret'], 'invasionIsInNormandy')
+ self.assertEqual(res_dict['user']['secret'], secret)
self.assertEqual(res_dict['user']['admin'], True)
self.assertTrue('test_guy' in [u.id for u in
fakes.FakeAuthManager.auth_data])
self.assertEqual(len(fakes.FakeAuthManager.auth_data), 3)
def test_user_update(self):
+ new_secret = utils.generate_password()
body = dict(user=dict(name='guy2',
access='acc2',
- secret='invasionIsInNormandy'))
- req = webob.Request.blank('/v1.0/users/guy2')
+ secret=new_secret))
+ req = webob.Request.blank('/v1.0/users/id2')
req.headers["Content-Type"] = "application/json"
req.method = 'PUT'
req.body = json.dumps(body)
@@ -132,8 +152,8 @@ class UsersTest(test.TestCase):
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 200)
- self.assertEqual(res_dict['user']['id'], 'guy2')
+ self.assertEqual(res_dict['user']['id'], 'id2')
self.assertEqual(res_dict['user']['name'], 'guy2')
self.assertEqual(res_dict['user']['access'], 'acc2')
- self.assertEqual(res_dict['user']['secret'], 'invasionIsInNormandy')
+ self.assertEqual(res_dict['user']['secret'], new_secret)
self.assertEqual(res_dict['user']['admin'], True)
--
cgit
From d95187aaf144cb40558f48d584a6bb8e07c6937d Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Wed, 16 Mar 2011 14:13:57 -0700
Subject: converted new lines from CRLF to LF
---
.../versions/012_add_ipv6_flatmanager.py | 302 +++++++++----------
nova/tests/network/__init__.py | 94 +++---
nova/tests/network/base.py | 308 ++++++++++----------
nova/tests/test_flat_network.py | 322 ++++++++++-----------
4 files changed, 513 insertions(+), 513 deletions(-)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
index 9f98f436f..5f5e3d007 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
@@ -1,151 +1,151 @@
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-from sqlalchemy import *
-from migrate import *
-
-from nova import log as logging
-
-
-meta = MetaData()
-
-
-# Table stub-definitions
-# Just for the ForeignKey and column creation to succeed, these are not the
-# actual definitions of instances or services.
-#
-
-#
-# Tables to alter
-#
-networks = Table('networks', meta,
- Column('created_at', DateTime(timezone=False)),
- Column('updated_at', DateTime(timezone=False)),
- Column('deleted_at', DateTime(timezone=False)),
- Column('deleted', Boolean(create_constraint=True, name=None)),
- Column('id', Integer(), primary_key=True, nullable=False),
- Column('injected', Boolean(create_constraint=True, name=None)),
- Column('cidr',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('netmask',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('bridge',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('gateway',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('broadcast',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('dns',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('vlan', Integer()),
- Column('vpn_public_address',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('vpn_public_port', Integer()),
- Column('vpn_private_address',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('dhcp_start',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('project_id',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('host',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('cidr_v6',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('ra_server', String(length=255,
- convert_unicode=False,
- assert_unicode=None,
- unicode_error=None,
- _warn_on_bytestring=False)),
- Column(
- 'label',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)))
-
-fixed_ips = Table('fixed_ips', meta,
- Column('created_at', DateTime(timezone=False)),
- Column('updated_at', DateTime(timezone=False)),
- Column('deleted_at', DateTime(timezone=False)),
- Column('deleted', Boolean(create_constraint=True, name=None)),
- Column('id', Integer(), primary_key=True, nullable=False),
- Column('address',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('network_id',
- Integer(),
- ForeignKey('networks.id'),
- nullable=True),
- Column('instance_id',
- Integer(),
- ForeignKey('instances.id'),
- nullable=True),
- Column('allocated', Boolean(create_constraint=True, name=None)),
- Column('leased', Boolean(create_constraint=True, name=None)),
- Column('reserved', Boolean(create_constraint=True, name=None)),
- Column("addressV6", String(length=255,
- convert_unicode=False,
- assert_unicode=None,
- unicode_error=None,
- _warn_on_bytestring=False)),
- Column("netmaskV6", String(length=3,
- convert_unicode=False,
- assert_unicode=None,
- unicode_error=None,
- _warn_on_bytestring=False)),
- Column("gatewayV6", String(length=255,
- convert_unicode=False,
- assert_unicode=None,
- unicode_error=None,
- _warn_on_bytestring=False)),
- )
-#
-# New Tables
-#
-# None
-
-#
-# Columns to add to existing tables
-#
-networks_netmask_v6 = Column(
- 'netmask_v6',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False))
-
-
-def upgrade(migrate_engine):
- # Upgrade operations go here. Don't create your own engine;
- # bind migrate_engine to your metadata
- meta.bind = migrate_engine
-
- # Alter column name
- networks.c.ra_server.alter(name='gateway_v6')
- # Add new column to existing table
- networks.create_column(networks_netmask_v6)
-
- # drop existing columns from table
- fixed_ips.c.addressV6.drop()
- fixed_ips.c.netmaskV6.drop()
- fixed_ips.c.gatewayV6.drop()
+# Copyright 2010 OpenStack LLC.
+# All Rights Reserved.
+#
+# 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.
+
+from sqlalchemy import *
+from migrate import *
+
+from nova import log as logging
+
+
+meta = MetaData()
+
+
+# Table stub-definitions
+# Just for the ForeignKey and column creation to succeed, these are not the
+# actual definitions of instances or services.
+#
+
+#
+# Tables to alter
+#
+networks = Table('networks', meta,
+ Column('created_at', DateTime(timezone=False)),
+ Column('updated_at', DateTime(timezone=False)),
+ Column('deleted_at', DateTime(timezone=False)),
+ Column('deleted', Boolean(create_constraint=True, name=None)),
+ Column('id', Integer(), primary_key=True, nullable=False),
+ Column('injected', Boolean(create_constraint=True, name=None)),
+ Column('cidr',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('netmask',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('bridge',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('gateway',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('broadcast',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('dns',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('vlan', Integer()),
+ Column('vpn_public_address',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('vpn_public_port', Integer()),
+ Column('vpn_private_address',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('dhcp_start',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('project_id',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('host',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('cidr_v6',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('ra_server', String(length=255,
+ convert_unicode=False,
+ assert_unicode=None,
+ unicode_error=None,
+ _warn_on_bytestring=False)),
+ Column(
+ 'label',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)))
+
+fixed_ips = Table('fixed_ips', meta,
+ Column('created_at', DateTime(timezone=False)),
+ Column('updated_at', DateTime(timezone=False)),
+ Column('deleted_at', DateTime(timezone=False)),
+ Column('deleted', Boolean(create_constraint=True, name=None)),
+ Column('id', Integer(), primary_key=True, nullable=False),
+ Column('address',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('network_id',
+ Integer(),
+ ForeignKey('networks.id'),
+ nullable=True),
+ Column('instance_id',
+ Integer(),
+ ForeignKey('instances.id'),
+ nullable=True),
+ Column('allocated', Boolean(create_constraint=True, name=None)),
+ Column('leased', Boolean(create_constraint=True, name=None)),
+ Column('reserved', Boolean(create_constraint=True, name=None)),
+ Column("addressV6", String(length=255,
+ convert_unicode=False,
+ assert_unicode=None,
+ unicode_error=None,
+ _warn_on_bytestring=False)),
+ Column("netmaskV6", String(length=3,
+ convert_unicode=False,
+ assert_unicode=None,
+ unicode_error=None,
+ _warn_on_bytestring=False)),
+ Column("gatewayV6", String(length=255,
+ convert_unicode=False,
+ assert_unicode=None,
+ unicode_error=None,
+ _warn_on_bytestring=False)),
+ )
+#
+# New Tables
+#
+# None
+
+#
+# Columns to add to existing tables
+#
+networks_netmask_v6 = Column(
+ 'netmask_v6',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False))
+
+
+def upgrade(migrate_engine):
+ # Upgrade operations go here. Don't create your own engine;
+ # bind migrate_engine to your metadata
+ meta.bind = migrate_engine
+
+ # Alter column name
+ networks.c.ra_server.alter(name='gateway_v6')
+ # Add new column to existing table
+ networks.create_column(networks_netmask_v6)
+
+ # drop existing columns from table
+ fixed_ips.c.addressV6.drop()
+ fixed_ips.c.netmaskV6.drop()
+ fixed_ips.c.gatewayV6.drop()
diff --git a/nova/tests/network/__init__.py b/nova/tests/network/__init__.py
index 8f71a30ba..e0d479f8c 100644
--- a/nova/tests/network/__init__.py
+++ b/nova/tests/network/__init__.py
@@ -1,47 +1,47 @@
-import os
-
-from nova import context
-from nova import db
-from nova import flags
-from nova import log as logging
-from nova import utils
-
-FLAGS = flags.FLAGS
-LOG = logging.getLogger('nova.tests.network')
-
-
-def binpath(script):
- """Returns the absolute path to a script in bin"""
- return os.path.abspath(os.path.join(__file__, "../../../../bin", script))
-
-
-def lease_ip(private_ip):
- """Run add command on dhcpbridge"""
- network_ref = db.fixed_ip_get_network(context.get_admin_context(),
- private_ip)
- instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
- private_ip)
- cmd = (binpath('nova-dhcpbridge'), 'add',
- instance_ref['mac_address'],
- private_ip, 'fake')
- env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
- 'TESTING': '1',
- 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
- (out, err) = utils.execute(*cmd, addl_env=env)
- LOG.debug("ISSUE_IP: %s, %s ", out, err)
-
-
-def release_ip(private_ip):
- """Run del command on dhcpbridge"""
- network_ref = db.fixed_ip_get_network(context.get_admin_context(),
- private_ip)
- instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
- private_ip)
- cmd = (binpath('nova-dhcpbridge'), 'del',
- instance_ref['mac_address'],
- private_ip, 'fake')
- env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
- 'TESTING': '1',
- 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
- (out, err) = utils.execute(*cmd, addl_env=env)
- LOG.debug("RELEASE_IP: %s, %s ", out, err)
+import os
+
+from nova import context
+from nova import db
+from nova import flags
+from nova import log as logging
+from nova import utils
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.network')
+
+
+def binpath(script):
+ """Returns the absolute path to a script in bin"""
+ return os.path.abspath(os.path.join(__file__, "../../../../bin", script))
+
+
+def lease_ip(private_ip):
+ """Run add command on dhcpbridge"""
+ network_ref = db.fixed_ip_get_network(context.get_admin_context(),
+ private_ip)
+ instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
+ private_ip)
+ cmd = (binpath('nova-dhcpbridge'), 'add',
+ instance_ref['mac_address'],
+ private_ip, 'fake')
+ env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
+ 'TESTING': '1',
+ 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
+ (out, err) = utils.execute(*cmd, addl_env=env)
+ LOG.debug("ISSUE_IP: %s, %s ", out, err)
+
+
+def release_ip(private_ip):
+ """Run del command on dhcpbridge"""
+ network_ref = db.fixed_ip_get_network(context.get_admin_context(),
+ private_ip)
+ instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
+ private_ip)
+ cmd = (binpath('nova-dhcpbridge'), 'del',
+ instance_ref['mac_address'],
+ private_ip, 'fake')
+ env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
+ 'TESTING': '1',
+ 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
+ (out, err) = utils.execute(*cmd, addl_env=env)
+ LOG.debug("RELEASE_IP: %s, %s ", out, err)
diff --git a/nova/tests/network/base.py b/nova/tests/network/base.py
index 2dd8178ff..988a1de72 100644
--- a/nova/tests/network/base.py
+++ b/nova/tests/network/base.py
@@ -1,154 +1,154 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# 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.
-"""
-Base class of Unit Tests for all network models
-"""
-import IPy
-import os
-
-from nova import context
-from nova import db
-from nova import exception
-from nova import flags
-from nova import log as logging
-from nova import test
-from nova import utils
-from nova.auth import manager
-
-FLAGS = flags.FLAGS
-LOG = logging.getLogger('nova.tests.network')
-
-
-class NetworkTestCase(test.TestCase):
- """Test cases for network code"""
- def setUp(self):
- super(NetworkTestCase, self).setUp()
- # NOTE(vish): if you change these flags, make sure to change the
- # flags in the corresponding section in nova-dhcpbridge
- self.flags(connection_type='fake',
- fake_call=True,
- fake_network=True)
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
- self.projects = []
- self.network = utils.import_object(FLAGS.network_manager)
- self.context = context.RequestContext(project=None, user=self.user)
- for i in range(FLAGS.num_networks):
- name = 'project%s' % i
- project = self.manager.create_project(name, 'netuser', name)
- self.projects.append(project)
- # create the necessary network data for the project
- user_context = context.RequestContext(project=self.projects[i],
- user=self.user)
- host = self.network.get_network_host(user_context.elevated())
- instance_ref = self._create_instance(0)
- self.instance_id = instance_ref['id']
- instance_ref = self._create_instance(1)
- self.instance2_id = instance_ref['id']
-
- def tearDown(self):
- # TODO(termie): this should really be instantiating clean datastores
- # in between runs, one failure kills all the tests
- db.instance_destroy(context.get_admin_context(), self.instance_id)
- db.instance_destroy(context.get_admin_context(), self.instance2_id)
- for project in self.projects:
- self.manager.delete_project(project)
- self.manager.delete_user(self.user)
- super(NetworkTestCase, self).tearDown()
-
- def _create_instance(self, project_num, mac=None):
- if not mac:
- mac = utils.generate_mac()
- project = self.projects[project_num]
- self.context._project = project
- self.context.project_id = project.id
- return db.instance_create(self.context,
- {'project_id': project.id,
- 'mac_address': mac})
-
- def _create_address(self, project_num, instance_id=None):
- """Create an address in given project num"""
- if instance_id is None:
- instance_id = self.instance_id
- self.context._project = self.projects[project_num]
- self.context.project_id = self.projects[project_num].id
- return self.network.allocate_fixed_ip(self.context, instance_id)
-
- def _deallocate_address(self, project_num, address):
- self.context._project = self.projects[project_num]
- self.context.project_id = self.projects[project_num].id
- self.network.deallocate_fixed_ip(self.context, address)
-
- def _is_allocated_in_project(self, address, project_id):
- """Returns true if address is in specified project"""
- project_net = db.network_get_by_bridge(context.get_admin_context(),
- FLAGS.flat_network_bridge)
- network = db.fixed_ip_get_network(context.get_admin_context(),
- address)
- instance = db.fixed_ip_get_instance(context.get_admin_context(),
- address)
- # instance exists until release
- return instance is not None and network['id'] == project_net['id']
-
- def test_private_ipv6(self):
- """Make sure ipv6 is OK"""
- if FLAGS.use_ipv6:
- instance_ref = self._create_instance(0)
- address = self._create_address(0, instance_ref['id'])
- network_ref = db.project_get_network(
- context.get_admin_context(),
- self.context.project_id)
- address_v6 = db.instance_get_fixed_address_v6(
- context.get_admin_context(),
- instance_ref['id'])
- self.assertEqual(instance_ref['mac_address'],
- utils.to_mac(address_v6))
- instance_ref2 = db.fixed_ip_get_instance_v6(
- context.get_admin_context(),
- address_v6)
- self.assertEqual(instance_ref['id'], instance_ref2['id'])
- self.assertEqual(address_v6,
- utils.to_global_ipv6(
- network_ref['cidr_v6'],
- instance_ref['mac_address']))
- self._deallocate_address(0, address)
- db.instance_destroy(context.get_admin_context(),
- instance_ref['id'])
-
- def test_available_ips(self):
- """Make sure the number of available ips for the network is correct
-
- The number of available IP addresses depends on the test
- environment's setup.
-
- Network size is set in test fixture's setUp method.
-
- There are ips reserved at the bottom and top of the range.
- services (network, gateway, CloudPipe, broadcast)
- """
- network = db.project_get_network(context.get_admin_context(),
- self.projects[0].id)
- net_size = flags.FLAGS.network_size
- admin_context = context.get_admin_context()
- total_ips = (db.network_count_available_ips(admin_context,
- network['id']) +
- db.network_count_reserved_ips(admin_context,
- network['id']) +
- db.network_count_allocated_ips(admin_context,
- network['id']))
- self.assertEqual(total_ips, net_size)
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# 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.
+"""
+Base class of Unit Tests for all network models
+"""
+import IPy
+import os
+
+from nova import context
+from nova import db
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import test
+from nova import utils
+from nova.auth import manager
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.network')
+
+
+class NetworkTestCase(test.TestCase):
+ """Test cases for network code"""
+ def setUp(self):
+ super(NetworkTestCase, self).setUp()
+ # NOTE(vish): if you change these flags, make sure to change the
+ # flags in the corresponding section in nova-dhcpbridge
+ self.flags(connection_type='fake',
+ fake_call=True,
+ fake_network=True)
+ self.manager = manager.AuthManager()
+ self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
+ self.projects = []
+ self.network = utils.import_object(FLAGS.network_manager)
+ self.context = context.RequestContext(project=None, user=self.user)
+ for i in range(FLAGS.num_networks):
+ name = 'project%s' % i
+ project = self.manager.create_project(name, 'netuser', name)
+ self.projects.append(project)
+ # create the necessary network data for the project
+ user_context = context.RequestContext(project=self.projects[i],
+ user=self.user)
+ host = self.network.get_network_host(user_context.elevated())
+ instance_ref = self._create_instance(0)
+ self.instance_id = instance_ref['id']
+ instance_ref = self._create_instance(1)
+ self.instance2_id = instance_ref['id']
+
+ def tearDown(self):
+ # TODO(termie): this should really be instantiating clean datastores
+ # in between runs, one failure kills all the tests
+ db.instance_destroy(context.get_admin_context(), self.instance_id)
+ db.instance_destroy(context.get_admin_context(), self.instance2_id)
+ for project in self.projects:
+ self.manager.delete_project(project)
+ self.manager.delete_user(self.user)
+ super(NetworkTestCase, self).tearDown()
+
+ def _create_instance(self, project_num, mac=None):
+ if not mac:
+ mac = utils.generate_mac()
+ project = self.projects[project_num]
+ self.context._project = project
+ self.context.project_id = project.id
+ return db.instance_create(self.context,
+ {'project_id': project.id,
+ 'mac_address': mac})
+
+ def _create_address(self, project_num, instance_id=None):
+ """Create an address in given project num"""
+ if instance_id is None:
+ instance_id = self.instance_id
+ self.context._project = self.projects[project_num]
+ self.context.project_id = self.projects[project_num].id
+ return self.network.allocate_fixed_ip(self.context, instance_id)
+
+ def _deallocate_address(self, project_num, address):
+ self.context._project = self.projects[project_num]
+ self.context.project_id = self.projects[project_num].id
+ self.network.deallocate_fixed_ip(self.context, address)
+
+ def _is_allocated_in_project(self, address, project_id):
+ """Returns true if address is in specified project"""
+ project_net = db.network_get_by_bridge(context.get_admin_context(),
+ FLAGS.flat_network_bridge)
+ network = db.fixed_ip_get_network(context.get_admin_context(),
+ address)
+ instance = db.fixed_ip_get_instance(context.get_admin_context(),
+ address)
+ # instance exists until release
+ return instance is not None and network['id'] == project_net['id']
+
+ def test_private_ipv6(self):
+ """Make sure ipv6 is OK"""
+ if FLAGS.use_ipv6:
+ instance_ref = self._create_instance(0)
+ address = self._create_address(0, instance_ref['id'])
+ network_ref = db.project_get_network(
+ context.get_admin_context(),
+ self.context.project_id)
+ address_v6 = db.instance_get_fixed_address_v6(
+ context.get_admin_context(),
+ instance_ref['id'])
+ self.assertEqual(instance_ref['mac_address'],
+ utils.to_mac(address_v6))
+ instance_ref2 = db.fixed_ip_get_instance_v6(
+ context.get_admin_context(),
+ address_v6)
+ self.assertEqual(instance_ref['id'], instance_ref2['id'])
+ self.assertEqual(address_v6,
+ utils.to_global_ipv6(
+ network_ref['cidr_v6'],
+ instance_ref['mac_address']))
+ self._deallocate_address(0, address)
+ db.instance_destroy(context.get_admin_context(),
+ instance_ref['id'])
+
+ def test_available_ips(self):
+ """Make sure the number of available ips for the network is correct
+
+ The number of available IP addresses depends on the test
+ environment's setup.
+
+ Network size is set in test fixture's setUp method.
+
+ There are ips reserved at the bottom and top of the range.
+ services (network, gateway, CloudPipe, broadcast)
+ """
+ network = db.project_get_network(context.get_admin_context(),
+ self.projects[0].id)
+ net_size = flags.FLAGS.network_size
+ admin_context = context.get_admin_context()
+ total_ips = (db.network_count_available_ips(admin_context,
+ network['id']) +
+ db.network_count_reserved_ips(admin_context,
+ network['id']) +
+ db.network_count_allocated_ips(admin_context,
+ network['id']))
+ self.assertEqual(total_ips, net_size)
diff --git a/nova/tests/test_flat_network.py b/nova/tests/test_flat_network.py
index b6f7762c5..dcc617e25 100644
--- a/nova/tests/test_flat_network.py
+++ b/nova/tests/test_flat_network.py
@@ -1,161 +1,161 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# 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.
-"""
-Unit Tests for flat network code
-"""
-import IPy
-import os
-import unittest
-
-from nova import context
-from nova import db
-from nova import exception
-from nova import flags
-from nova import log as logging
-from nova import test
-from nova import utils
-from nova.auth import manager
-from nova.tests.network import base
-
-
-FLAGS = flags.FLAGS
-LOG = logging.getLogger('nova.tests.network')
-
-
-class FlatNetworkTestCase(base.NetworkTestCase):
- """Test cases for network code"""
- def test_public_network_association(self):
- """Makes sure that we can allocate a public ip"""
- # TODO(vish): better way of adding floating ips
-
- self.context._project = self.projects[0]
- self.context.project_id = self.projects[0].id
- pubnet = IPy.IP(flags.FLAGS.floating_range)
- address = str(pubnet[0])
- try:
- db.floating_ip_get_by_address(context.get_admin_context(), address)
- except exception.NotFound:
- db.floating_ip_create(context.get_admin_context(),
- {'address': address,
- 'host': FLAGS.host})
-
- self.assertRaises(NotImplementedError,
- self.network.allocate_floating_ip,
- self.context, self.projects[0].id)
-
- fix_addr = self._create_address(0)
- float_addr = address
- self.assertRaises(NotImplementedError,
- self.network.associate_floating_ip,
- self.context, float_addr, fix_addr)
-
- address = db.instance_get_floating_address(context.get_admin_context(),
- self.instance_id)
- self.assertEqual(address, None)
-
- self.assertRaises(NotImplementedError,
- self.network.disassociate_floating_ip,
- self.context, float_addr)
-
- address = db.instance_get_floating_address(context.get_admin_context(),
- self.instance_id)
- self.assertEqual(address, None)
-
- self.assertRaises(NotImplementedError,
- self.network.deallocate_floating_ip,
- self.context, float_addr)
-
- self.network.deallocate_fixed_ip(self.context, fix_addr)
- db.floating_ip_destroy(context.get_admin_context(), float_addr)
-
- def test_allocate_deallocate_fixed_ip(self):
- """Makes sure that we can allocate and deallocate a fixed ip"""
- address = self._create_address(0)
- self.assertTrue(self._is_allocated_in_project(address,
- self.projects[0].id))
- self._deallocate_address(0, address)
-
- # check if the fixed ip address is really deallocated
- self.assertFalse(self._is_allocated_in_project(address,
- self.projects[0].id))
-
- def test_side_effects(self):
- """Ensures allocating and releasing has no side effects"""
- address = self._create_address(0)
- address2 = self._create_address(1, self.instance2_id)
-
- self.assertTrue(self._is_allocated_in_project(address,
- self.projects[0].id))
- self.assertTrue(self._is_allocated_in_project(address2,
- self.projects[1].id))
-
- self._deallocate_address(0, address)
- self.assertFalse(self._is_allocated_in_project(address,
- self.projects[0].id))
-
- # First address release shouldn't affect the second
- self.assertTrue(self._is_allocated_in_project(address2,
- self.projects[0].id))
-
- self._deallocate_address(1, address2)
- self.assertFalse(self._is_allocated_in_project(address2,
- self.projects[1].id))
-
- def test_ips_are_reused(self):
- """Makes sure that ip addresses that are deallocated get reused"""
- address = self._create_address(0)
- self.network.deallocate_fixed_ip(self.context, address)
-
- address2 = self._create_address(0)
- self.assertEqual(address, address2)
-
- self.network.deallocate_fixed_ip(self.context, address2)
-
- def test_too_many_addresses(self):
- """Test for a NoMoreAddresses exception when all fixed ips are used.
- """
- admin_context = context.get_admin_context()
- network = db.project_get_network(admin_context, self.projects[0].id)
- num_available_ips = db.network_count_available_ips(admin_context,
- network['id'])
- addresses = []
- instance_ids = []
- for i in range(num_available_ips):
- instance_ref = self._create_instance(0)
- instance_ids.append(instance_ref['id'])
- address = self._create_address(0, instance_ref['id'])
- addresses.append(address)
-
- ip_count = db.network_count_available_ips(context.get_admin_context(),
- network['id'])
- self.assertEqual(ip_count, 0)
- self.assertRaises(db.NoMoreAddresses,
- self.network.allocate_fixed_ip,
- self.context,
- 'foo')
-
- for i in range(num_available_ips):
- self.network.deallocate_fixed_ip(self.context, addresses[i])
- db.instance_destroy(context.get_admin_context(), instance_ids[i])
- ip_count = db.network_count_available_ips(context.get_admin_context(),
- network['id'])
- self.assertEqual(ip_count, num_available_ips)
-
- def run(self, result=None):
- if(FLAGS.network_manager == 'nova.network.manager.FlatManager'):
- super(FlatNetworkTestCase, self).run(result)
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# 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.
+"""
+Unit Tests for flat network code
+"""
+import IPy
+import os
+import unittest
+
+from nova import context
+from nova import db
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import test
+from nova import utils
+from nova.auth import manager
+from nova.tests.network import base
+
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.network')
+
+
+class FlatNetworkTestCase(base.NetworkTestCase):
+ """Test cases for network code"""
+ def test_public_network_association(self):
+ """Makes sure that we can allocate a public ip"""
+ # TODO(vish): better way of adding floating ips
+
+ self.context._project = self.projects[0]
+ self.context.project_id = self.projects[0].id
+ pubnet = IPy.IP(flags.FLAGS.floating_range)
+ address = str(pubnet[0])
+ try:
+ db.floating_ip_get_by_address(context.get_admin_context(), address)
+ except exception.NotFound:
+ db.floating_ip_create(context.get_admin_context(),
+ {'address': address,
+ 'host': FLAGS.host})
+
+ self.assertRaises(NotImplementedError,
+ self.network.allocate_floating_ip,
+ self.context, self.projects[0].id)
+
+ fix_addr = self._create_address(0)
+ float_addr = address
+ self.assertRaises(NotImplementedError,
+ self.network.associate_floating_ip,
+ self.context, float_addr, fix_addr)
+
+ address = db.instance_get_floating_address(context.get_admin_context(),
+ self.instance_id)
+ self.assertEqual(address, None)
+
+ self.assertRaises(NotImplementedError,
+ self.network.disassociate_floating_ip,
+ self.context, float_addr)
+
+ address = db.instance_get_floating_address(context.get_admin_context(),
+ self.instance_id)
+ self.assertEqual(address, None)
+
+ self.assertRaises(NotImplementedError,
+ self.network.deallocate_floating_ip,
+ self.context, float_addr)
+
+ self.network.deallocate_fixed_ip(self.context, fix_addr)
+ db.floating_ip_destroy(context.get_admin_context(), float_addr)
+
+ def test_allocate_deallocate_fixed_ip(self):
+ """Makes sure that we can allocate and deallocate a fixed ip"""
+ address = self._create_address(0)
+ self.assertTrue(self._is_allocated_in_project(address,
+ self.projects[0].id))
+ self._deallocate_address(0, address)
+
+ # check if the fixed ip address is really deallocated
+ self.assertFalse(self._is_allocated_in_project(address,
+ self.projects[0].id))
+
+ def test_side_effects(self):
+ """Ensures allocating and releasing has no side effects"""
+ address = self._create_address(0)
+ address2 = self._create_address(1, self.instance2_id)
+
+ self.assertTrue(self._is_allocated_in_project(address,
+ self.projects[0].id))
+ self.assertTrue(self._is_allocated_in_project(address2,
+ self.projects[1].id))
+
+ self._deallocate_address(0, address)
+ self.assertFalse(self._is_allocated_in_project(address,
+ self.projects[0].id))
+
+ # First address release shouldn't affect the second
+ self.assertTrue(self._is_allocated_in_project(address2,
+ self.projects[0].id))
+
+ self._deallocate_address(1, address2)
+ self.assertFalse(self._is_allocated_in_project(address2,
+ self.projects[1].id))
+
+ def test_ips_are_reused(self):
+ """Makes sure that ip addresses that are deallocated get reused"""
+ address = self._create_address(0)
+ self.network.deallocate_fixed_ip(self.context, address)
+
+ address2 = self._create_address(0)
+ self.assertEqual(address, address2)
+
+ self.network.deallocate_fixed_ip(self.context, address2)
+
+ def test_too_many_addresses(self):
+ """Test for a NoMoreAddresses exception when all fixed ips are used.
+ """
+ admin_context = context.get_admin_context()
+ network = db.project_get_network(admin_context, self.projects[0].id)
+ num_available_ips = db.network_count_available_ips(admin_context,
+ network['id'])
+ addresses = []
+ instance_ids = []
+ for i in range(num_available_ips):
+ instance_ref = self._create_instance(0)
+ instance_ids.append(instance_ref['id'])
+ address = self._create_address(0, instance_ref['id'])
+ addresses.append(address)
+
+ ip_count = db.network_count_available_ips(context.get_admin_context(),
+ network['id'])
+ self.assertEqual(ip_count, 0)
+ self.assertRaises(db.NoMoreAddresses,
+ self.network.allocate_fixed_ip,
+ self.context,
+ 'foo')
+
+ for i in range(num_available_ips):
+ self.network.deallocate_fixed_ip(self.context, addresses[i])
+ db.instance_destroy(context.get_admin_context(), instance_ids[i])
+ ip_count = db.network_count_available_ips(context.get_admin_context(),
+ network['id'])
+ self.assertEqual(ip_count, num_available_ips)
+
+ def run(self, result=None):
+ if(FLAGS.network_manager == 'nova.network.manager.FlatManager'):
+ super(FlatNetworkTestCase, self).run(result)
--
cgit
From 1aa44c3d8d0a22c5c5bc432d191a15656ad3351d Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Wed, 16 Mar 2011 14:34:44 -0700
Subject: Don't complain about the _ function being used
---
pylintrc | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/pylintrc b/pylintrc
index f07b14980..53cf37719 100644
--- a/pylintrc
+++ b/pylintrc
@@ -1,3 +1,5 @@
+# The format of this file isn't really documented; just use --generate-rcfile
+
[Messages Control]
# W0511: TODOs in code comments are fine.
# W0142: *args and **kwargs are fine.
@@ -25,3 +27,10 @@ no-docstring-rgx=((__.*__)|([tT]est.*)|setUp|tearDown)$
max-public-methods=100
min-public-methods=0
max-args=6
+
+[Variables]
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+# _ is used by our localization
+additional-builtins=_
--
cgit
From a151fabdb7f3edef8ba17b204fe55c73fc15720a Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Wed, 16 Mar 2011 15:25:21 -0700
Subject: In order to disable the messages, we have to use disable, not
disable-msg.
---
pylintrc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pylintrc b/pylintrc
index 53cf37719..378479ec5 100644
--- a/pylintrc
+++ b/pylintrc
@@ -4,7 +4,7 @@
# W0511: TODOs in code comments are fine.
# W0142: *args and **kwargs are fine.
# W0622: Redefining id is fine.
-disable-msg=W0511,W0142,W0622
+disable=W0511,W0142,W0622
[Basic]
# Variable names can be 1 to 31 characters long, with lowercase and underscores
--
cgit
From 7b7033bfb31c610b1f0295e6059ed44931dfe450 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Wed, 16 Mar 2011 15:28:09 -0700
Subject: Don't warn about C0111 (No docstrings)
While docstrings are great, requiring them is probably going too far. Let's get pylint useful first by having it not complain too much, then we can have a second stricter PyLint if desired.
---
pylintrc | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/pylintrc b/pylintrc
index 378479ec5..135eea4d5 100644
--- a/pylintrc
+++ b/pylintrc
@@ -1,10 +1,12 @@
# The format of this file isn't really documented; just use --generate-rcfile
[Messages Control]
+# NOTE(justinsb): We might want to have a 2nd strict pylintrc in future
+# C0111: Don't require docstrings on every method
# W0511: TODOs in code comments are fine.
# W0142: *args and **kwargs are fine.
# W0622: Redefining id is fine.
-disable=W0511,W0142,W0622
+disable=C0111,W0511,W0142,W0622
[Basic]
# Variable names can be 1 to 31 characters long, with lowercase and underscores
--
cgit
From adb9c0f0d933f8a56e688b89cfa632ce5c9e4888 Mon Sep 17 00:00:00 2001
From: Trey Morris
Date: Wed, 16 Mar 2011 17:48:39 -0500
Subject: commit before monster
---
nova/virt/xenapi/vmops.py | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 27f9a3a17..fbc7ab64d 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -761,10 +761,11 @@ class VMOps(object):
mac_address, device)
device += 1
- def reset_network(self, instance):
+ def reset_network(self, instance, vm_ref):
"""Creates uuid arg to pass to make_agent_call and calls it."""
args = {'id': str(uuid.uuid4())}
- resp = self._make_agent_call('resetnetwork', instance, '', args)
+ resp = self._make_agent_call('resetnetwork', instance, '', args,
+ vm_ref)
def list_from_xenstore(self, vm, path):
"""Runs the xenstore-ls command to get a listing of all records
@@ -805,25 +806,27 @@ class VMOps(object):
"""
self._make_xenstore_call('delete_record', vm, path)
- def _make_xenstore_call(self, method, vm, path, addl_args={}):
+ def _make_xenstore_call(self, method, vm, path, addl_args=None,
+ vm_ref=None):
"""Handles calls to the xenstore xenapi plugin."""
return self._make_plugin_call('xenstore.py', method=method, vm=vm,
- path=path, addl_args=addl_args)
+ path=path, addl_args=addl_args, vm_ref=vm_ref)
- def _make_agent_call(self, method, vm, path, addl_args={}):
+ def _make_agent_call(self, method, vm, path, addl_args=None, vm_ref=None):
"""Abstracts out the interaction with the agent xenapi plugin."""
return self._make_plugin_call('agent', method=method, vm=vm,
- path=path, addl_args=addl_args)
+ path=path, addl_args=addl_args, vm_ref=vm_ref)
- def _make_plugin_call(self, plugin, method, vm, path, addl_args={}):
+ def _make_plugin_call(self, plugin, method, vm, path, addl_args=None,
+ vm_ref=None):
"""Abstracts out the process of calling a method of a xenapi plugin.
Any errors raised by the plugin will in turn raise a RuntimeError here.
"""
instance_id = vm.id
- vm_ref = self._get_vm_opaque_ref(vm)
+ vm_ref = vm_ref or self._get_vm_opaque_ref(vm)
vm_rec = self._session.get_xenapi().VM.get_record(vm_ref)
args = {'dom_id': vm_rec['domid'], 'path': path}
- args.update(addl_args)
+ args.update(addl_args or {})
try:
task = self._session.async_call_plugin(plugin, method, args)
ret = self._session.wait_for_task(task, instance_id)
--
cgit
From 038d99d9fa4354bd617adfa332d69a87a9f7918e Mon Sep 17 00:00:00 2001
From: Trey Morris
Date: Wed, 16 Mar 2011 18:18:07 -0500
Subject: hacks in place
---
nova/virt/xenapi/vmops.py | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index fbc7ab64d..a9a6800b1 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -137,7 +137,7 @@ class VMOps(object):
networks = db.network_get_all_by_instance(admin_context,
instance['id'])
network_info = self._get_network_info(instance, networks, IPs)
- self.inject_network_info(vm_ref, network_info)
+ self.inject_network_info(instance, vm_ref, network_info)
self.create_vifs(vm_ref, network_info)
LOG.debug(_('Starting VM %s...'), vm_ref)
@@ -188,7 +188,7 @@ class VMOps(object):
timer.f = _wait_for_boot
# call to reset network to configure network from xenstore
- self.reset_network(instance)
+ self.reset_network(instance, vm_ref)
return timer.start(interval=0.5, now=True)
@@ -724,7 +724,7 @@ class VMOps(object):
network_info.append((network, info))
return network_info
- def inject_network_info(self, vm_ref, network_info):
+ def inject_network_info(self, instance, vm_ref, network_info):
"""
Generate the network info and make calls to place it into the
xenstore and the xenstore param list
@@ -738,7 +738,11 @@ class VMOps(object):
location = 'vm-data/networking/%s' % info['mac'].replace(':', '')
self.write_to_param_xenstore(vm_ref, {location: info})
try:
- self.write_to_xenstore(vm_ref, location, info)
+ # TODO(tr3buchet): fix function call after refactor
+ #self.write_to_xenstore(vm_ref, location, info)
+ self._make_plugin_call('xenstore.py', 'write_record', instance,
+ location, {'value': json.dumps(info)},
+ vm_ref)
except KeyError:
# catch KeyError for domid if instance isn't running
pass
@@ -764,8 +768,10 @@ class VMOps(object):
def reset_network(self, instance, vm_ref):
"""Creates uuid arg to pass to make_agent_call and calls it."""
args = {'id': str(uuid.uuid4())}
- resp = self._make_agent_call('resetnetwork', instance, '', args,
- vm_ref)
+ # TODO(tr3buchet): fix function call after refactor
+ #resp = self._make_agent_call('resetnetwork', instance, '', args)
+ resp = self._make_plugin_call('agent', 'resetnetwork', instance, '',
+ args, vm_ref)
def list_from_xenstore(self, vm, path):
"""Runs the xenstore-ls command to get a listing of all records
@@ -806,16 +812,15 @@ class VMOps(object):
"""
self._make_xenstore_call('delete_record', vm, path)
- def _make_xenstore_call(self, method, vm, path, addl_args=None,
- vm_ref=None):
+ def _make_xenstore_call(self, method, vm, path, addl_args=None):
"""Handles calls to the xenstore xenapi plugin."""
return self._make_plugin_call('xenstore.py', method=method, vm=vm,
- path=path, addl_args=addl_args, vm_ref=vm_ref)
+ path=path, addl_args=addl_args)
- def _make_agent_call(self, method, vm, path, addl_args=None, vm_ref=None):
+ def _make_agent_call(self, method, vm, path, addl_args=None):
"""Abstracts out the interaction with the agent xenapi plugin."""
return self._make_plugin_call('agent', method=method, vm=vm,
- path=path, addl_args=addl_args, vm_ref=vm_ref)
+ path=path, addl_args=addl_args)
def _make_plugin_call(self, plugin, method, vm, path, addl_args=None,
vm_ref=None):
--
cgit
From 27d5cbaf03e532e30de2b6aacbc330391a0d1735 Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Thu, 17 Mar 2011 14:51:59 +0100
Subject: Make smoketests' exit code reveal whether they were succesful.
---
smoketests/admin_smoketests.py | 2 +-
smoketests/base.py | 9 +++++++--
smoketests/netadmin_smoketests.py | 2 +-
smoketests/public_network_smoketests.py | 2 +-
smoketests/sysadmin_smoketests.py | 2 +-
5 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/smoketests/admin_smoketests.py b/smoketests/admin_smoketests.py
index 86a7f600d..8d8b4349e 100644
--- a/smoketests/admin_smoketests.py
+++ b/smoketests/admin_smoketests.py
@@ -95,4 +95,4 @@ class UserTests(AdminSmokeTestCase):
if __name__ == "__main__":
suites = {'user': unittest.makeSuite(UserTests)}
- sys.exit(base.run_tests(suites))
+ sys.exit(not base.run_tests(suites))
diff --git a/smoketests/base.py b/smoketests/base.py
index 204b4a1eb..11f67ed6f 100644
--- a/smoketests/base.py
+++ b/smoketests/base.py
@@ -205,7 +205,12 @@ def run_tests(suites):
', '.join(suites.keys())
return 1
- unittest.TextTestRunner(verbosity=2).run(suite)
+ return unittest.TextTestRunner(verbosity=2).run(suite).wasSuccessful()
else:
+ successful = True
for suite in suites.itervalues():
- unittest.TextTestRunner(verbosity=2).run(suite)
+ result = unittest.TextTestRunner(verbosity=2).run(suite)
+ if not result.wasSuccesful():
+ successful = False
+ return successful
+
diff --git a/smoketests/netadmin_smoketests.py b/smoketests/netadmin_smoketests.py
index 38beb8fdc..4aa97c4e2 100644
--- a/smoketests/netadmin_smoketests.py
+++ b/smoketests/netadmin_smoketests.py
@@ -191,4 +191,4 @@ if __name__ == "__main__":
suites = {'address': unittest.makeSuite(AddressTests),
'security_group': unittest.makeSuite(SecurityGroupTests)
}
- sys.exit(base.run_tests(suites))
+ sys.exit(not base.run_tests(suites))
diff --git a/smoketests/public_network_smoketests.py b/smoketests/public_network_smoketests.py
index 5a4c67642..8a2ae3379 100644
--- a/smoketests/public_network_smoketests.py
+++ b/smoketests/public_network_smoketests.py
@@ -184,4 +184,4 @@ class InstanceTestsFromPublic(base.UserSmokeTestCase):
if __name__ == "__main__":
suites = {'instance': unittest.makeSuite(InstanceTestsFromPublic)}
- sys.exit(base.run_tests(suites))
+ sys.exit(not base.run_tests(suites))
diff --git a/smoketests/sysadmin_smoketests.py b/smoketests/sysadmin_smoketests.py
index e3b84d3d3..6648ae7cf 100644
--- a/smoketests/sysadmin_smoketests.py
+++ b/smoketests/sysadmin_smoketests.py
@@ -290,4 +290,4 @@ if __name__ == "__main__":
'instance': unittest.makeSuite(InstanceTests),
'volume': unittest.makeSuite(VolumeTests)
}
- sys.exit(base.run_tests(suites))
+ sys.exit(not base.run_tests(suites))
--
cgit
From d31e0f0ad048fbd0374170ea76968859a4c6df34 Mon Sep 17 00:00:00 2001
From: Brian Lamar
Date: Thu, 17 Mar 2011 12:39:09 -0400
Subject: Fixed pep8 violation.
---
nova/api/openstack/faults.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/nova/api/openstack/faults.py b/nova/api/openstack/faults.py
index d05c61fc7..56f5b8e7e 100644
--- a/nova/api/openstack/faults.py
+++ b/nova/api/openstack/faults.py
@@ -94,5 +94,6 @@ class OverLimitFault(webob.exc.HTTPException):
"""Currently just return the wrapped exception."""
serializer = wsgi.Serializer(self._serialization_metadata)
content_type = request.best_match_content_type()
- self.wrapped_exc.body = serializer.serialize(self.content, content_type)
+ content = serializer.serialize(self.content, content_type)
+ self.wrapped_exc.body = content
return self.wrapped_exc
--
cgit
From f96dea3da633fc71f16de1bdb95e88249b316e29 Mon Sep 17 00:00:00 2001
From: Brian Lamar
Date: Thu, 17 Mar 2011 13:11:40 -0400
Subject: Pep8 error, oddly specific to pep8 v0.5 < x > v0.6
---
nova/api/openstack/faults.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/nova/api/openstack/faults.py b/nova/api/openstack/faults.py
index 56f5b8e7e..ccccbd3d2 100644
--- a/nova/api/openstack/faults.py
+++ b/nova/api/openstack/faults.py
@@ -71,9 +71,9 @@ class OverLimitFault(webob.exc.HTTPException):
_serialization_metadata = {
"application/xml": {
"attributes": {
- "overLimitFault": "code"
- }
- }
+ "overLimitFault": "code",
+ },
+ },
}
def __init__(self, message, details, retry_time):
--
cgit
From 6d6d0f686a7f8d47263b7ed725bdae0f322b2a4e Mon Sep 17 00:00:00 2001
From: Ken Pepple
Date: Thu, 17 Mar 2011 11:34:14 -0700
Subject: better implementation of try..except..else
---
nova/image/local.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/nova/image/local.py b/nova/image/local.py
index c304a2212..609d6c42a 100644
--- a/nova/image/local.py
+++ b/nova/image/local.py
@@ -53,13 +53,13 @@ class LocalImageService(service.BaseImageService):
images = []
for image_dir in os.listdir(self._path):
try:
- images.append(int(image_dir, 16))
+ unhexed_image_id = int(image_dir, 16)
except ValueError:
LOG.error(
_("%s is not in correct directory naming format"\
% image_dir))
- except:
- raise
+ else:
+ images.append(unhexed_image_id)
return images
def index(self, context):
--
cgit
From 3628f50b4ecd2db0377fd9c158248d3b7e8e98ff Mon Sep 17 00:00:00 2001
From: Brian Lamar
Date: Thu, 17 Mar 2011 16:26:52 -0400
Subject: Better comment for fault. Improved readability of two small sections.
---
nova/api/openstack/faults.py | 5 ++++-
nova/api/openstack/limits.py | 2 +-
nova/tests/api/openstack/test_limits.py | 2 +-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/nova/api/openstack/faults.py b/nova/api/openstack/faults.py
index ccccbd3d2..0e9c4b26f 100644
--- a/nova/api/openstack/faults.py
+++ b/nova/api/openstack/faults.py
@@ -91,7 +91,10 @@ class OverLimitFault(webob.exc.HTTPException):
@webob.dec.wsgify(RequestClass=wsgi.Request)
def __call__(self, request):
- """Currently just return the wrapped exception."""
+ """
+ Return the wrapped exception with a serialized body conforming to our
+ error format.
+ """
serializer = wsgi.Serializer(self._serialization_metadata)
content_type = request.best_match_content_type()
content = serializer.serialize(self.content, content_type)
diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py
index 1fe519f8a..efc7d193d 100644
--- a/nova/api/openstack/limits.py
+++ b/nova/api/openstack/limits.py
@@ -151,7 +151,7 @@ class Limit(object):
water = self.water_level
val = self.value
- self.remaining = math.floor((cap - water) / cap * val)
+ self.remaining = math.floor(((cap - water) / cap) * val)
self.next_request = now
def _get_time(self):
diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py
index d1db93a59..05cfacc60 100644
--- a/nova/tests/api/openstack/test_limits.py
+++ b/nova/tests/api/openstack/test_limits.py
@@ -273,7 +273,7 @@ class LimiterTest(BaseLimitTestSuite):
def _check_sum(self, num, verb, url, username=None):
"""Check and sum results from checks."""
results = self._check(num, verb, url, username)
- return sum(filter(lambda x: x != None, results))
+ return sum(item for item in results if item)
def test_no_delay_GET(self):
"""
--
cgit
From ccad7a5d36d27a1854d12d3e45d1c6099983e56c Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Thu, 17 Mar 2011 13:29:22 -0700
Subject: Mark instance metadata as deleted when we delete the instance
---
nova/db/sqlalchemy/api.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 44540617f..2bfe9a52a 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -797,6 +797,11 @@ def instance_destroy(context, instance_id):
update({'deleted': 1,
'deleted_at': datetime.datetime.utcnow(),
'updated_at': literal_column('updated_at')})
+ session.query(models.InstanceMetadata).\
+ filter_by(instance_id=instance_id).\
+ update({'deleted': 1,
+ 'deleted_at': datetime.datetime.utcnow(),
+ 'updated_at': literal_column('updated_at')})
@require_context
--
cgit
From a437ea845bd83c8b1da9de81253132cbad6b48b7 Mon Sep 17 00:00:00 2001
From: Trey Morris
Date: Thu, 17 Mar 2011 16:14:48 -0500
Subject: create vifs before inject network info to remove rxtx_cap from
network info (don't need to inject it)
---
nova/virt/xenapi/vmops.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index a35d36b9e..aff4fb445 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -133,8 +133,8 @@ class VMOps(object):
# create it now. This goes away once nova-multi-nic hits.
if network_info is None:
network_info = self._get_network_info(instance)
- self.inject_network_info(instance, vm_ref, network_info)
self.create_vifs(vm_ref, network_info)
+ self.inject_network_info(instance, vm_ref, network_info)
LOG.debug(_('Starting VM %s...'), vm_ref)
self._start(instance, vm_ref)
--
cgit
From b05bdeaf77ccb91ac59b4a2dde4a6cad94eb22b2 Mon Sep 17 00:00:00 2001
From: Trey Morris
Date: Thu, 17 Mar 2011 16:17:03 -0500
Subject: syntax error
---
nova/virt/xenapi/vmops.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index aff4fb445..6542630c1 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -698,7 +698,7 @@ class VMOps(object):
networks = db.network_get_all_by_instance(admin_context,
instance['id'])
flavor = db.instance_type_get_by_name(admin_context,
- instance.['instance_type'])
+ instance['instance_type'])
network_info = []
for network in networks:
network_IPs = [ip for ip in IPs if ip.network_id == network.id]
--
cgit
From e2d66aaa670817bda9bf1b494b6a4cfde32b6daf Mon Sep 17 00:00:00 2001
From: Anthony Young
Date: Thu, 17 Mar 2011 14:28:03 -0700
Subject: fix for lp712982, and likely a variety of other dashboard error
handling issues. This fix simply causes the default error code for ApiError
to be 'ApiError' rather than 'Unknown', which makes dashboard handle the
error gracefully, and makes euca error output slightly prettier
---
nova/exception.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/exception.py b/nova/exception.py
index 93c5fe3d7..4e2bbdbaf 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -46,7 +46,7 @@ class Error(Exception):
class ApiError(Error):
- def __init__(self, message='Unknown', code='Unknown'):
+ def __init__(self, message='Unknown', code='ApiError'):
self.message = message
self.code = code
super(ApiError, self).__init__('%s: %s' % (code, message))
--
cgit
From 385b513822dff84e2faeb7f1d1b60efdf3d82fab Mon Sep 17 00:00:00 2001
From: Josh Kleinpeter
Date: Thu, 17 Mar 2011 15:09:09 -0700
Subject: Made fixed_range a required parameter for nova-manage network create.
Changed default num_networks to 1; 1000 seems large.
---
bin/nova-manage | 5 +++--
nova/network/manager.py | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/bin/nova-manage b/bin/nova-manage
index a4d820209..0c39b662c 100755
--- a/bin/nova-manage
+++ b/bin/nova-manage
@@ -518,11 +518,12 @@ class NetworkCommands(object):
network_size=None, vlan_start=None,
vpn_start=None, fixed_range_v6=None, label='public'):
"""Creates fixed ips for host by range
- arguments: [fixed_range=FLAG], [num_networks=FLAG],
+ arguments: fixed_range=FLAG, [num_networks=FLAG],
[network_size=FLAG], [vlan_start=FLAG],
[vpn_start=FLAG], [fixed_range_v6=FLAG]"""
if not fixed_range:
- fixed_range = FLAGS.fixed_range
+ raise ValueError('Fixed range in the form of 10.0.0.0/8 is '
+ 'required to create networks.')
if not num_networks:
num_networks = FLAGS.num_networks
if not network_size:
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 3dfc48934..f2025af06 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -73,7 +73,7 @@ flags.DEFINE_string('flat_interface', None,
flags.DEFINE_string('flat_network_dhcp_start', '10.0.0.2',
'Dhcp start for FlatDhcp')
flags.DEFINE_integer('vlan_start', 100, 'First VLAN for private networks')
-flags.DEFINE_integer('num_networks', 1000, 'Number of networks to support')
+flags.DEFINE_integer('num_networks', 1, 'Number of networks to support')
flags.DEFINE_string('vpn_ip', '$my_ip',
'Public IP for the cloudpipe VPN servers')
flags.DEFINE_integer('vpn_start', 1000, 'First Vpn port for private networks')
--
cgit
From 57e3d5abb539031b0d5d40e9033aef43de917fef Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Thu, 17 Mar 2011 23:37:34 +0100
Subject: Make the smoketests pep8 compliant (they weren't when I started
working on them..)
---
smoketests/base.py | 1 -
smoketests/sysadmin_smoketests.py | 4 ++--
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/smoketests/base.py b/smoketests/base.py
index 11f67ed6f..d367d7944 100644
--- a/smoketests/base.py
+++ b/smoketests/base.py
@@ -213,4 +213,3 @@ def run_tests(suites):
if not result.wasSuccesful():
successful = False
return successful
-
diff --git a/smoketests/sysadmin_smoketests.py b/smoketests/sysadmin_smoketests.py
index 6648ae7cf..1e593e963 100644
--- a/smoketests/sysadmin_smoketests.py
+++ b/smoketests/sysadmin_smoketests.py
@@ -34,8 +34,6 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
from smoketests import flags
from smoketests import base
-
-
FLAGS = flags.FLAGS
flags.DEFINE_string('bundle_kernel', 'openwrt-x86-vmlinuz',
'Local kernel file to use for bundling tests')
@@ -46,6 +44,8 @@ TEST_PREFIX = 'test%s' % int(random.random() * 1000000)
TEST_BUCKET = '%s_bucket' % TEST_PREFIX
TEST_KEY = '%s_key' % TEST_PREFIX
TEST_GROUP = '%s_group' % TEST_PREFIX
+
+
class ImageTests(base.UserSmokeTestCase):
def test_001_can_bundle_image(self):
self.assertTrue(self.bundle_image(FLAGS.bundle_image))
--
cgit
From 83523c125af0fcdc740373332bd5a2d4f233dd0e Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Thu, 17 Mar 2011 23:45:35 +0100
Subject: Invert some of the original logic and fix a typo.
---
smoketests/base.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/smoketests/base.py b/smoketests/base.py
index d367d7944..59c7b415c 100644
--- a/smoketests/base.py
+++ b/smoketests/base.py
@@ -203,13 +203,13 @@ def run_tests(suites):
except KeyError:
print >> sys.stderr, 'Available test suites:', \
', '.join(suites.keys())
- return 1
+ return False
return unittest.TextTestRunner(verbosity=2).run(suite).wasSuccessful()
else:
successful = True
for suite in suites.itervalues():
result = unittest.TextTestRunner(verbosity=2).run(suite)
- if not result.wasSuccesful():
+ if not result.wasSuccessful():
successful = False
return successful
--
cgit
From 4940654f04c50c8593f8e5486fa9e4998f2a3fc7 Mon Sep 17 00:00:00 2001
From: Todd Willey
Date: Thu, 17 Mar 2011 19:32:25 -0400
Subject: Changing project manager should make sure that user is a project
member.
---
nova/auth/dbdriver.py | 2 ++
nova/auth/ldapdriver.py | 2 ++
nova/tests/test_auth.py | 7 +++++++
3 files changed, 11 insertions(+)
diff --git a/nova/auth/dbdriver.py b/nova/auth/dbdriver.py
index d8dad8edd..d1e3f2ed5 100644
--- a/nova/auth/dbdriver.py
+++ b/nova/auth/dbdriver.py
@@ -162,6 +162,8 @@ class DbDriver(object):
values['description'] = description
db.project_update(context.get_admin_context(), project_id, values)
+ if not self.is_in_project(manager_uid, project_id):
+ self.add_to_project(manager_uid, project_id)
def add_to_project(self, uid, project_id):
"""Add user to project"""
diff --git a/nova/auth/ldapdriver.py b/nova/auth/ldapdriver.py
index 5da7751a0..647f70db1 100644
--- a/nova/auth/ldapdriver.py
+++ b/nova/auth/ldapdriver.py
@@ -275,6 +275,8 @@ class LdapDriver(object):
attr.append((self.ldap.MOD_REPLACE, 'description', description))
dn = self.__project_to_dn(project_id)
self.conn.modify_s(dn, attr)
+ if not self.is_in_project(manager_uid, project_id):
+ self.add_to_project(manager_uid, project_id)
@sanitize
def add_to_project(self, uid, project_id):
diff --git a/nova/tests/test_auth.py b/nova/tests/test_auth.py
index 2a7817032..885596f56 100644
--- a/nova/tests/test_auth.py
+++ b/nova/tests/test_auth.py
@@ -299,6 +299,13 @@ class AuthManagerTestCase(object):
self.assertEqual('test2', project.project_manager_id)
self.assertEqual('new desc', project.description)
+ def test_modify_project_adds_new_manager(self):
+ with user_and_project_generator(self.manager):
+ with user_generator(self.manager, name='test2'):
+ self.manager.modify_project('testproj', 'test2', 'new desc')
+ project = self.manager.get_project('testproj')
+ self.assertTrue('test2' in project.member_ids)
+
def test_can_delete_project(self):
with user_generator(self.manager):
self.manager.create_project('testproj', 'test1')
--
cgit
From 79ed4a643df34029391685e13f04e3bfb8afa215 Mon Sep 17 00:00:00 2001
From: Todd Willey
Date: Thu, 17 Mar 2011 19:41:16 -0400
Subject: Add topic name to cast/call logs.
---
nova/rpc.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/nova/rpc.py b/nova/rpc.py
index fbb90299b..58715963a 100644
--- a/nova/rpc.py
+++ b/nova/rpc.py
@@ -311,7 +311,7 @@ def _pack_context(msg, context):
def call(context, topic, msg):
"""Sends a message on a topic and wait for a response"""
- LOG.debug(_("Making asynchronous call..."))
+ LOG.debug(_("Making asynchronous call on %s ..."), topic)
msg_id = uuid.uuid4().hex
msg.update({'_msg_id': msg_id})
LOG.debug(_("MSG_ID is %s") % (msg_id))
@@ -352,7 +352,7 @@ def call(context, topic, msg):
def cast(context, topic, msg):
"""Sends a message on a topic without waiting for a response"""
- LOG.debug(_("Making asynchronous cast..."))
+ LOG.debug(_("Making asynchronous cast on %s..."), topic)
_pack_context(msg, context)
conn = Connection.instance()
publisher = TopicPublisher(connection=conn, topic=topic)
--
cgit
From 59d2a315b87fad6d88a31994546d99d859f1849b Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Thu, 17 Mar 2011 18:26:20 -0700
Subject: Fix for LP Bug #737240
---
contrib/boto_v6/ec2/connection.py | 98 +++++++++++++++++++++++++++++++++++++++
smoketests/sysadmin_smoketests.py | 12 ++---
2 files changed, 104 insertions(+), 6 deletions(-)
diff --git a/contrib/boto_v6/ec2/connection.py b/contrib/boto_v6/ec2/connection.py
index 23466e5d7..faecae95e 100644
--- a/contrib/boto_v6/ec2/connection.py
+++ b/contrib/boto_v6/ec2/connection.py
@@ -39,3 +39,101 @@ class EC2ConnectionV6(boto.ec2.EC2Connection):
self.build_filter_params(params, filters)
return self.get_list('DescribeInstancesV6', params,
[('item', ReservationV6)])
+
+ def run_instances(self, image_id, min_count=1, max_count=1,
+ key_name=None, security_groups=None,
+ user_data=None, addressing_type=None,
+ instance_type='m1.small', placement=None,
+ kernel_id=None, ramdisk_id=None,
+ monitoring_enabled=False, subnet_id=None,
+ block_device_map=None):
+ """
+ Runs an image on EC2.
+
+ :type image_id: string
+ :param image_id: The ID of the image to run
+
+ :type min_count: int
+ :param min_count: The minimum number of instances to launch
+
+ :type max_count: int
+ :param max_count: The maximum number of instances to launch
+
+ :type key_name: string
+ :param key_name: The name of the key pair with which to
+ launch instances
+
+ :type security_groups: list of strings
+ :param security_groups: The names of the security groups with
+ which to associate instances
+
+ :type user_data: string
+ :param user_data: The user data passed to the launched instances
+
+ :type instance_type: string
+ :param instance_type: The type of instance to run
+ (m1.small, m1.large, m1.xlarge)
+
+ :type placement: string
+ :param placement: The availability zone in which to launch
+ the instances
+
+ :type kernel_id: string
+ :param kernel_id: The ID of the kernel with which to
+ launch the instances
+
+ :type ramdisk_id: string
+ :param ramdisk_id: The ID of the RAM disk with which to
+ launch the instances
+
+ :type monitoring_enabled: bool
+ :param monitoring_enabled: Enable CloudWatch monitoring
+ on the instance.
+
+ :type subnet_id: string
+ :param subnet_id: The subnet ID within which to launch
+ the instances for VPC.
+
+ :type block_device_map:
+ :class:`boto.ec2.blockdevicemapping.BlockDeviceMapping`
+ :param block_device_map: A BlockDeviceMapping data structure
+ describing the EBS volumes associated
+ with the Image.
+
+ :rtype: Reservation
+ :return: The :class:`boto.ec2.instance.Reservation`
+ associated with the request for machines
+ """
+ params = {'ImageId': image_id,
+ 'MinCount': min_count,
+ 'MaxCount': max_count}
+ if key_name:
+ params['KeyName'] = key_name
+ if security_groups:
+ l = []
+ for group in security_groups:
+ if isinstance(group, SecurityGroup):
+ l.append(group.name)
+ else:
+ l.append(group)
+ self.build_list_params(params, l, 'SecurityGroup')
+ if user_data:
+ params['UserData'] = base64.b64encode(user_data)
+ if addressing_type:
+ params['AddressingType'] = addressing_type
+ if instance_type:
+ params['InstanceType'] = instance_type
+ if placement:
+ params['Placement.AvailabilityZone'] = placement
+ if kernel_id:
+ params['KernelId'] = kernel_id
+ if ramdisk_id:
+ params['RamdiskId'] = ramdisk_id
+ if monitoring_enabled:
+ params['Monitoring.Enabled'] = 'true'
+ if subnet_id:
+ params['SubnetId'] = subnet_id
+ if block_device_map:
+ block_device_map.build_list_params(params)
+ return self.get_object('RunInstances', params,
+ ReservationV6, verb='POST')
diff --git a/smoketests/sysadmin_smoketests.py b/smoketests/sysadmin_smoketests.py
index e3b84d3d3..e92cc1881 100644
--- a/smoketests/sysadmin_smoketests.py
+++ b/smoketests/sysadmin_smoketests.py
@@ -34,8 +34,6 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
from smoketests import flags
from smoketests import base
-
-
FLAGS = flags.FLAGS
flags.DEFINE_string('bundle_kernel', 'openwrt-x86-vmlinuz',
'Local kernel file to use for bundling tests')
@@ -46,6 +44,8 @@ TEST_PREFIX = 'test%s' % int(random.random() * 1000000)
TEST_BUCKET = '%s_bucket' % TEST_PREFIX
TEST_KEY = '%s_key' % TEST_PREFIX
TEST_GROUP = '%s_group' % TEST_PREFIX
+
+
class ImageTests(base.UserSmokeTestCase):
def test_001_can_bundle_image(self):
self.assertTrue(self.bundle_image(FLAGS.bundle_image))
@@ -148,7 +148,8 @@ class InstanceTests(base.UserSmokeTestCase):
self.fail('could not ping instance')
if FLAGS.use_ipv6:
- if not self.wait_for_ping(self.data['instance'].ip_v6, "ping6"):
+ if not self.wait_for_ping(self.data['instance'].dns_name_v6,
+ "ping6"):
self.fail('could not ping instance v6')
def test_005_can_ssh_to_private_ip(self):
@@ -157,7 +158,7 @@ class InstanceTests(base.UserSmokeTestCase):
self.fail('could not ssh to instance')
if FLAGS.use_ipv6:
- if not self.wait_for_ssh(self.data['instance'].ip_v6,
+ if not self.wait_for_ssh(self.data['instance'].dns_name_v6,
TEST_KEY):
self.fail('could not ssh to instance v6')
@@ -286,8 +287,7 @@ class VolumeTests(base.UserSmokeTestCase):
if __name__ == "__main__":
- suites = {'image': unittest.makeSuite(ImageTests),
+ suites = {
'instance': unittest.makeSuite(InstanceTests),
- 'volume': unittest.makeSuite(VolumeTests)
}
sys.exit(base.run_tests(suites))
--
cgit
From 51ed0ccf8d841443561a476a03c3446844e1a0a8 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Thu, 17 Mar 2011 18:54:51 -0700
Subject: Fix for LP Bug #737240
---
smoketests/sysadmin_smoketests.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/smoketests/sysadmin_smoketests.py b/smoketests/sysadmin_smoketests.py
index e92cc1881..2bfc1ac88 100644
--- a/smoketests/sysadmin_smoketests.py
+++ b/smoketests/sysadmin_smoketests.py
@@ -285,9 +285,8 @@ class VolumeTests(base.UserSmokeTestCase):
self.conn.terminate_instances([self.data['instance'].id])
self.conn.delete_key_pair(TEST_KEY)
-
if __name__ == "__main__":
- suites = {
+ suites = {'image': unittest.makeSuite(ImageTests),
'instance': unittest.makeSuite(InstanceTests),
- }
+ 'volume': unittest.makeSuite(VolumeTests)}
sys.exit(base.run_tests(suites))
--
cgit
From 9608ef7d49dd5181f45bd458cea676f79116c39f Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Fri, 18 Mar 2011 11:06:58 +0100
Subject: Query the size of the block device, not the size of the filesystem.
---
smoketests/sysadmin_smoketests.py | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/smoketests/sysadmin_smoketests.py b/smoketests/sysadmin_smoketests.py
index 1e593e963..3adb1e0f0 100644
--- a/smoketests/sysadmin_smoketests.py
+++ b/smoketests/sysadmin_smoketests.py
@@ -255,12 +255,13 @@ class VolumeTests(base.UserSmokeTestCase):
ip = self.data['instance'].private_dns_name
conn = self.connect_ssh(ip, TEST_KEY)
stdin, stdout, stderr = conn.exec_command(
- "df -h | grep %s | awk {'print $2'}" % self.device)
- out = stdout.read()
+ "blockdev --getsize64 %s" % self.device)
+ out = stdout.read().strip()
conn.close()
- if not out.strip() == '1007.9M':
- self.fail('Volume is not the right size: %s %s' %
- (out, stderr.read()))
+ expected_size = 1024*1024*1024
+ self.assertEquals('%s' % (expected_size,), out,
+ 'Volume is not the right size: %s %s. Expected: %s' %
+ (out, stderr.read(), expected_size))
def test_006_me_can_umount_volume(self):
ip = self.data['instance'].private_dns_name
--
cgit
From 9eb64af0d7182f19fd7eda75371e202022f79891 Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Fri, 18 Mar 2011 11:27:38 +0100
Subject: Make proxy.sh work with both openbsd and traditional variants of
netcat.
---
smoketests/proxy.sh | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/smoketests/proxy.sh b/smoketests/proxy.sh
index 9b3f3108a..b9057fe9d 100755
--- a/smoketests/proxy.sh
+++ b/smoketests/proxy.sh
@@ -11,12 +11,19 @@
mkfifo backpipe1
mkfifo backpipe2
+if nc -h 2>&1 | grep -i openbsd
+then
+ NC_LISTEN="nc -l"
+else
+ NC_LISTEN="nc -l -p"
+fi
+
# NOTE(vish): proxy metadata on port 80
while true; do
- nc -l -p 80 0backpipe1
+ $NC_LISTEN 80 0backpipe1
done &
# NOTE(vish): proxy google on port 8080
while true; do
- nc -l -p 8080 0backpipe2
+ $NC_LISTEN 8080 0backpipe2
done &
--
cgit
From 6e632e9ef2907f0b00d3026379af03abe5024bc7 Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Fri, 18 Mar 2011 13:14:37 +0100
Subject: Make flag parsing work again.
---
smoketests/run_tests.py | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/smoketests/run_tests.py b/smoketests/run_tests.py
index 4f06f0f2b..e7f6eced7 100644
--- a/smoketests/run_tests.py
+++ b/smoketests/run_tests.py
@@ -60,12 +60,23 @@ import os
import unittest
import sys
+# If ../nova/__init__.py exists, add ../ to Python search path, so that
+# it will override what happens to be installed in /usr/(local/)lib/python...
+possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
+ os.pardir,
+ os.pardir))
+if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
+ sys.path.insert(0, possible_topdir)
+
+
gettext.install('nova', unicode=1)
from nose import config
from nose import core
from nose import result
+from smoketests import flags
+FLAGS = flags.FLAGS
class _AnsiColorizer(object):
"""
@@ -284,6 +295,7 @@ if __name__ == '__main__':
'running this test.')
sys.exit(1)
+ argv = FLAGS(sys.argv)
testdir = os.path.abspath("./")
c = config.Config(stream=sys.stdout,
env=os.environ,
@@ -294,4 +306,4 @@ if __name__ == '__main__':
runner = NovaTestRunner(stream=c.stream,
verbosity=c.verbosity,
config=c)
- sys.exit(not core.run(config=c, testRunner=runner, argv=sys.argv))
+ sys.exit(not core.run(config=c, testRunner=runner, argv=argv))
--
cgit
From 4b18488223d2c51958855456cb4f5877f331aaa1 Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Fri, 18 Mar 2011 13:17:40 +0100
Subject: PEP-8
---
smoketests/base.py | 1 -
smoketests/run_tests.py | 1 +
smoketests/test_sysadmin.py | 4 ++--
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/smoketests/base.py b/smoketests/base.py
index d32d4766c..3e2446c9a 100644
--- a/smoketests/base.py
+++ b/smoketests/base.py
@@ -190,4 +190,3 @@ class UserSmokeTestCase(SmokeTestCase):
global TEST_DATA
self.conn = self.connection_for_env()
self.data = TEST_DATA
-
diff --git a/smoketests/run_tests.py b/smoketests/run_tests.py
index e7f6eced7..62bdfbec6 100644
--- a/smoketests/run_tests.py
+++ b/smoketests/run_tests.py
@@ -78,6 +78,7 @@ from nose import result
from smoketests import flags
FLAGS = flags.FLAGS
+
class _AnsiColorizer(object):
"""
A colorizer is an object that loosely wraps around a stream, allowing
diff --git a/smoketests/test_sysadmin.py b/smoketests/test_sysadmin.py
index 40339869d..15c3b9d57 100644
--- a/smoketests/test_sysadmin.py
+++ b/smoketests/test_sysadmin.py
@@ -265,10 +265,10 @@ class VolumeTests(base.UserSmokeTestCase):
ip = self.data['instance'].private_dns_name
conn = self.connect_ssh(ip, TEST_KEY)
stdin, stdout, stderr = conn.exec_command(
- "blockdev --getsize64 %s" % self.device)
+ "blockdev --getsize64 %s" % self.device)
out = stdout.read().strip()
conn.close()
- expected_size = 1024*1024*1024
+ expected_size = 1024 * 1024 * 1024
self.assertEquals('%s' % (expected_size,), out,
'Volume is not the right size: %s %s. Expected: %s' %
(out, stderr.read(), expected_size))
--
cgit
From 6e9a95fe81c389c672b5150d64749b274975f7bc Mon Sep 17 00:00:00 2001
From: Brian Lamar
Date: Fri, 18 Mar 2011 09:56:05 -0400
Subject: disable-msg -> disable
---
bin/nova-ajax-console-proxy | 2 +-
bin/nova-api | 2 +-
bin/nova-direct-api | 2 +-
bin/nova-instancemonitor | 2 +-
bin/nova-objectstore | 2 +-
nova/auth/fakeldap.py | 8 ++++----
nova/auth/ldapdriver.py | 2 +-
nova/auth/manager.py | 2 +-
nova/compute/manager.py | 4 ++--
nova/db/api.py | 2 +-
nova/db/base.py | 2 +-
nova/db/sqlalchemy/api.py | 2 +-
nova/network/linux_net.py | 6 +++---
nova/network/manager.py | 4 ++--
nova/objectstore/handler.py | 14 +++++++-------
nova/rpc.py | 6 +++---
nova/service.py | 2 +-
nova/tests/api/test_wsgi.py | 2 +-
nova/tests/hyperv_unittest.py | 2 +-
nova/tests/objectstore_unittest.py | 8 ++++----
nova/tests/test_api.py | 2 +-
nova/tests/test_middleware.py | 4 ++--
po/nova.pot | 10 +++++-----
tools/euca-get-ajax-console | 2 +-
24 files changed, 47 insertions(+), 47 deletions(-)
diff --git a/bin/nova-ajax-console-proxy b/bin/nova-ajax-console-proxy
index bbd60bade..b4ba157e1 100755
--- a/bin/nova-ajax-console-proxy
+++ b/bin/nova-ajax-console-proxy
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# pylint: disable-msg=C0103
+# pylint: disable=C0103
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
diff --git a/bin/nova-api b/bin/nova-api
index 06bb855cb..a1088c23d 100755
--- a/bin/nova-api
+++ b/bin/nova-api
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# pylint: disable-msg=C0103
+# pylint: disable=C0103
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
diff --git a/bin/nova-direct-api b/bin/nova-direct-api
index bf29d9a5e..a2c9f1557 100755
--- a/bin/nova-direct-api
+++ b/bin/nova-direct-api
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# pylint: disable-msg=C0103
+# pylint: disable=C0103
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
diff --git a/bin/nova-instancemonitor b/bin/nova-instancemonitor
index 24cc9fd23..b9d4e49d7 100755
--- a/bin/nova-instancemonitor
+++ b/bin/nova-instancemonitor
@@ -50,7 +50,7 @@ if __name__ == '__main__':
if __name__ == '__builtin__':
LOG.warn(_('Starting instance monitor'))
- # pylint: disable-msg=C0103
+ # pylint: disable=C0103
monitor = monitor.InstanceMonitor()
# This is the parent service that twistd will be looking for when it
diff --git a/bin/nova-objectstore b/bin/nova-objectstore
index 9fbe228a2..94ef2a8d5 100755
--- a/bin/nova-objectstore
+++ b/bin/nova-objectstore
@@ -49,4 +49,4 @@ if __name__ == '__main__':
twistd.serve(__file__)
if __name__ == '__builtin__':
- application = handler.get_application() # pylint: disable-msg=C0103
+ application = handler.get_application() # pylint: disable=C0103
diff --git a/nova/auth/fakeldap.py b/nova/auth/fakeldap.py
index 4466051f0..e8f5771d5 100644
--- a/nova/auth/fakeldap.py
+++ b/nova/auth/fakeldap.py
@@ -90,12 +90,12 @@ MOD_DELETE = 1
MOD_REPLACE = 2
-class NO_SUCH_OBJECT(Exception): # pylint: disable-msg=C0103
+class NO_SUCH_OBJECT(Exception): # pylint: disable=C0103
"""Duplicate exception class from real LDAP module."""
pass
-class OBJECT_CLASS_VIOLATION(Exception): # pylint: disable-msg=C0103
+class OBJECT_CLASS_VIOLATION(Exception): # pylint: disable=C0103
"""Duplicate exception class from real LDAP module."""
pass
@@ -268,7 +268,7 @@ class FakeLDAP(object):
# get the attributes from the store
attrs = store.hgetall(key)
# turn the values from the store into lists
- # pylint: disable-msg=E1103
+ # pylint: disable=E1103
attrs = dict([(k, _from_json(v))
for k, v in attrs.iteritems()])
# filter the objects by query
@@ -283,6 +283,6 @@ class FakeLDAP(object):
return objects
@property
- def __prefix(self): # pylint: disable-msg=R0201
+ def __prefix(self): # pylint: disable=R0201
"""Get the prefix to use for all keys."""
return 'ldap:'
diff --git a/nova/auth/ldapdriver.py b/nova/auth/ldapdriver.py
index 647f70db1..fcac55510 100644
--- a/nova/auth/ldapdriver.py
+++ b/nova/auth/ldapdriver.py
@@ -634,6 +634,6 @@ class LdapDriver(object):
class FakeLdapDriver(LdapDriver):
"""Fake Ldap Auth driver"""
- def __init__(self): # pylint: disable-msg=W0231
+ def __init__(self): # pylint: disable=W0231
__import__('nova.auth.fakeldap')
self.ldap = sys.modules['nova.auth.fakeldap']
diff --git a/nova/auth/manager.py b/nova/auth/manager.py
index 450ab803a..29811ea16 100644
--- a/nova/auth/manager.py
+++ b/nova/auth/manager.py
@@ -22,7 +22,7 @@ Nova authentication management
import os
import shutil
-import string # pylint: disable-msg=W0402
+import string # pylint: disable=W0402
import tempfile
import uuid
import zipfile
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 92deca813..c2781f6fb 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -220,7 +220,7 @@ class ComputeManager(manager.Manager):
self.db.instance_update(context,
instance_id,
{'launched_at': now})
- except Exception: # pylint: disable-msg=W0702
+ except Exception: # pylint: disable=W0702
LOG.exception(_("instance %s: Failed to spawn"), instance_id,
context=context)
self.db.instance_set_state(context,
@@ -692,7 +692,7 @@ class ComputeManager(manager.Manager):
volume_id,
instance_id,
mountpoint)
- except Exception as exc: # pylint: disable-msg=W0702
+ except Exception as exc: # pylint: disable=W0702
# NOTE(vish): The inline callback eats the exception info so we
# log the traceback here and reraise the same
# ecxception below.
diff --git a/nova/db/api.py b/nova/db/api.py
index 3cb0e5811..94777f413 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -608,7 +608,7 @@ def network_get_all(context):
return IMPL.network_get_all(context)
-# pylint: disable-msg=C0103
+# pylint: disable=C0103
def network_get_associated_fixed_ips(context, network_id):
"""Get all network's ips that have been associated."""
return IMPL.network_get_associated_fixed_ips(context, network_id)
diff --git a/nova/db/base.py b/nova/db/base.py
index 1d1e80866..a0f2180c6 100644
--- a/nova/db/base.py
+++ b/nova/db/base.py
@@ -33,4 +33,4 @@ class Base(object):
def __init__(self, db_driver=None):
if not db_driver:
db_driver = FLAGS.db_driver
- self.db = utils.import_object(db_driver) # pylint: disable-msg=C0103
+ self.db = utils.import_object(db_driver) # pylint: disable=C0103
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 9d9b86c1d..394d9a90a 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -1249,7 +1249,7 @@ def network_get_all(context):
# NOTE(vish): pylint complains because of the long method name, but
# it fits with the names of the rest of the methods
-# pylint: disable-msg=C0103
+# pylint: disable=C0103
@require_admin_context
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index 7106e6164..565732869 100644
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -582,7 +582,7 @@ def update_dhcp(context, network_id):
try:
_execute('sudo', 'kill', '-HUP', pid)
return
- except Exception as exc: # pylint: disable-msg=W0703
+ except Exception as exc: # pylint: disable=W0703
LOG.debug(_("Hupping dnsmasq threw %s"), exc)
else:
LOG.debug(_("Pid %d is stale, relaunching dnsmasq"), pid)
@@ -626,7 +626,7 @@ interface %s
if conffile in out:
try:
_execute('sudo', 'kill', pid)
- except Exception as exc: # pylint: disable-msg=W0703
+ except Exception as exc: # pylint: disable=W0703
LOG.debug(_("killing radvd threw %s"), exc)
else:
LOG.debug(_("Pid %d is stale, relaunching radvd"), pid)
@@ -713,7 +713,7 @@ def _stop_dnsmasq(network):
if pid:
try:
_execute('sudo', 'kill', '-TERM', pid)
- except Exception as exc: # pylint: disable-msg=W0703
+ except Exception as exc: # pylint: disable=W0703
LOG.debug(_("Killing dnsmasq threw %s"), exc)
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 3dfc48934..0decb126a 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -322,12 +322,12 @@ class NetworkManager(manager.Manager):
self._create_fixed_ips(context, network_ref['id'])
@property
- def _bottom_reserved_ips(self): # pylint: disable-msg=R0201
+ def _bottom_reserved_ips(self): # pylint: disable=R0201
"""Number of reserved ips at the bottom of the range."""
return 2 # network, gateway
@property
- def _top_reserved_ips(self): # pylint: disable-msg=R0201
+ def _top_reserved_ips(self): # pylint: disable=R0201
"""Number of reserved ips at the top of the range."""
return 1 # broadcast
diff --git a/nova/objectstore/handler.py b/nova/objectstore/handler.py
index 05ddace4b..554c72848 100644
--- a/nova/objectstore/handler.py
+++ b/nova/objectstore/handler.py
@@ -167,7 +167,7 @@ class S3(ErrorHandlingResource):
def __init__(self):
ErrorHandlingResource.__init__(self)
- def getChild(self, name, request): # pylint: disable-msg=C0103
+ def getChild(self, name, request): # pylint: disable=C0103
"""Returns either the image or bucket resource"""
request.context = get_context(request)
if name == '':
@@ -177,7 +177,7 @@ class S3(ErrorHandlingResource):
else:
return BucketResource(name)
- def render_GET(self, request): # pylint: disable-msg=R0201
+ def render_GET(self, request): # pylint: disable=R0201
"""Renders the GET request for a list of buckets as XML"""
LOG.debug(_('List of buckets requested'), context=request.context)
buckets = [b for b in bucket.Bucket.all()
@@ -355,7 +355,7 @@ class ImagesResource(resource.Resource):
else:
return ImageResource(name)
- def render_GET(self, request): # pylint: disable-msg=R0201
+ def render_GET(self, request): # pylint: disable=R0201
""" returns a json listing of all images
that a user has permissions to see """
@@ -384,7 +384,7 @@ class ImagesResource(resource.Resource):
request.finish()
return server.NOT_DONE_YET
- def render_PUT(self, request): # pylint: disable-msg=R0201
+ def render_PUT(self, request): # pylint: disable=R0201
""" create a new registered image """
image_id = get_argument(request, 'image_id', u'')
@@ -413,7 +413,7 @@ class ImagesResource(resource.Resource):
p.start()
return ''
- def render_POST(self, request): # pylint: disable-msg=R0201
+ def render_POST(self, request): # pylint: disable=R0201
"""Update image attributes: public/private"""
# image_id required for all requests
@@ -441,7 +441,7 @@ class ImagesResource(resource.Resource):
image_object.update_user_editable_fields(clean_args)
return ''
- def render_DELETE(self, request): # pylint: disable-msg=R0201
+ def render_DELETE(self, request): # pylint: disable=R0201
"""Delete a registered image"""
image_id = get_argument(request, "image_id", u"")
image_object = image.Image(image_id)
@@ -471,7 +471,7 @@ def get_application():
application = service.Application("objectstore")
# Disabled because of lack of proper introspection in Twisted
# or possibly different versions of twisted?
- # pylint: disable-msg=E1101
+ # pylint: disable=E1101
objectStoreService = internet.TCPServer(FLAGS.s3_port, factory,
interface=FLAGS.s3_listen_host)
objectStoreService.setServiceParent(application)
diff --git a/nova/rpc.py b/nova/rpc.py
index 58715963a..5935e1fb3 100644
--- a/nova/rpc.py
+++ b/nova/rpc.py
@@ -62,7 +62,7 @@ class Connection(carrot_connection.BrokerConnection):
params['backend_cls'] = fakerabbit.Backend
# NOTE(vish): magic is fun!
- # pylint: disable-msg=W0142
+ # pylint: disable=W0142
if new:
return cls(**params)
else:
@@ -114,7 +114,7 @@ class Consumer(messaging.Consumer):
if self.failed_connection:
# NOTE(vish): connection is defined in the parent class, we can
# recreate it as long as we create the backend too
- # pylint: disable-msg=W0201
+ # pylint: disable=W0201
self.connection = Connection.recreate()
self.backend = self.connection.create_backend()
self.declare()
@@ -125,7 +125,7 @@ class Consumer(messaging.Consumer):
# NOTE(vish): This is catching all errors because we really don't
# want exceptions to be logged 10 times a second if some
# persistent failure occurs.
- except Exception: # pylint: disable-msg=W0703
+ except Exception: # pylint: disable=W0703
if not self.failed_connection:
LOG.exception(_("Failed to fetch message from queue"))
self.failed_connection = True
diff --git a/nova/service.py b/nova/service.py
index d60df987c..52bb15ad7 100644
--- a/nova/service.py
+++ b/nova/service.py
@@ -217,7 +217,7 @@ class Service(object):
logging.error(_("Recovered model server connection!"))
# TODO(vish): this should probably only catch connection errors
- except Exception: # pylint: disable-msg=W0702
+ except Exception: # pylint: disable=W0702
if not getattr(self, "model_disconnected", False):
self.model_disconnected = True
logging.exception(_("model server went away"))
diff --git a/nova/tests/api/test_wsgi.py b/nova/tests/api/test_wsgi.py
index b1a849cf9..1ecdd1cfb 100644
--- a/nova/tests/api/test_wsgi.py
+++ b/nova/tests/api/test_wsgi.py
@@ -80,7 +80,7 @@ class ControllerTest(test.TestCase):
"attributes": {
"test": ["id"]}}}
- def show(self, req, id): # pylint: disable-msg=W0622,C0103
+ def show(self, req, id): # pylint: disable=W0622,C0103
return {"test": {"id": id}}
def __init__(self):
diff --git a/nova/tests/hyperv_unittest.py b/nova/tests/hyperv_unittest.py
index 3980ae3cb..042819b9c 100644
--- a/nova/tests/hyperv_unittest.py
+++ b/nova/tests/hyperv_unittest.py
@@ -51,7 +51,7 @@ class HyperVTestCase(test.TestCase):
instance_ref = db.instance_create(self.context, instance)
conn = hyperv.get_connection(False)
- conn._create_vm(instance_ref) # pylint: disable-msg=W0212
+ conn._create_vm(instance_ref) # pylint: disable=W0212
found = [n for n in conn.list_instances()
if n == instance_ref['name']]
self.assertTrue(len(found) == 1)
diff --git a/nova/tests/objectstore_unittest.py b/nova/tests/objectstore_unittest.py
index 5a1be08eb..5d160bdf8 100644
--- a/nova/tests/objectstore_unittest.py
+++ b/nova/tests/objectstore_unittest.py
@@ -179,7 +179,7 @@ class ObjectStoreTestCase(test.TestCase):
class TestHTTPChannel(http.HTTPChannel):
"""Dummy site required for twisted.web"""
- def checkPersistence(self, _, __): # pylint: disable-msg=C0103
+ def checkPersistence(self, _, __): # pylint: disable=C0103
"""Otherwise we end up with an unclean reactor."""
return False
@@ -209,7 +209,7 @@ class S3APITestCase(test.TestCase):
root = S3()
self.site = TestSite(root)
- # pylint: disable-msg=E1101
+ # pylint: disable=E1101
self.listening_port = reactor.listenTCP(0, self.site,
interface='127.0.0.1')
# pylint: enable-msg=E1101
@@ -231,11 +231,11 @@ class S3APITestCase(test.TestCase):
self.conn.get_http_connection = get_http_connection
- def _ensure_no_buckets(self, buckets): # pylint: disable-msg=C0111
+ def _ensure_no_buckets(self, buckets): # pylint: disable=C0111
self.assertEquals(len(buckets), 0, "Bucket list was not empty")
return True
- def _ensure_one_bucket(self, buckets, name): # pylint: disable-msg=C0111
+ def _ensure_one_bucket(self, buckets, name): # pylint: disable=C0111
self.assertEquals(len(buckets), 1,
"Bucket list didn't have exactly one element in it")
self.assertEquals(buckets[0].name, name, "Wrong name")
diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py
index d5c54a1c3..b67d6b12c 100644
--- a/nova/tests/test_api.py
+++ b/nova/tests/test_api.py
@@ -124,7 +124,7 @@ class ApiEc2TestCase(test.TestCase):
self.mox.StubOutWithMock(self.ec2, 'new_http_connection')
self.http = FakeHttplibConnection(
self.app, '%s:8773' % (self.host), False)
- # pylint: disable-msg=E1103
+ # pylint: disable=E1103
self.ec2.new_http_connection(host, is_secure).AndReturn(self.http)
return self.http
diff --git a/nova/tests/test_middleware.py b/nova/tests/test_middleware.py
index 9d49167ba..6564a6955 100644
--- a/nova/tests/test_middleware.py
+++ b/nova/tests/test_middleware.py
@@ -40,12 +40,12 @@ def conditional_forbid(req):
class LockoutTestCase(test.TestCase):
"""Test case for the Lockout middleware."""
- def setUp(self): # pylint: disable-msg=C0103
+ def setUp(self): # pylint: disable=C0103
super(LockoutTestCase, self).setUp()
utils.set_time_override()
self.lockout = ec2.Lockout(conditional_forbid)
- def tearDown(self): # pylint: disable-msg=C0103
+ def tearDown(self): # pylint: disable=C0103
utils.clear_time_override()
super(LockoutTestCase, self).tearDown()
diff --git a/po/nova.pot b/po/nova.pot
index ce88d731b..58140302d 100644
--- a/po/nova.pot
+++ b/po/nova.pot
@@ -300,7 +300,7 @@ msgstr ""
msgid "instance %s: starting..."
msgstr ""
-#. pylint: disable-msg=W0702
+#. pylint: disable=W0702
#: ../nova/compute/manager.py:219
#, python-format
msgid "instance %s: Failed to spawn"
@@ -440,7 +440,7 @@ msgid ""
"instance %(instance_id)s: attaching volume %(volume_id)s to %(mountpoint)s"
msgstr ""
-#. pylint: disable-msg=W0702
+#. pylint: disable=W0702
#. NOTE(vish): The inline callback eats the exception info so we
#. log the traceback here and reraise the same
#. ecxception below.
@@ -591,7 +591,7 @@ msgstr ""
msgid "Starting Bridge interface for %s"
msgstr ""
-#. pylint: disable-msg=W0703
+#. pylint: disable=W0703
#: ../nova/network/linux_net.py:314
#, python-format
msgid "Hupping dnsmasq threw %s"
@@ -602,7 +602,7 @@ msgstr ""
msgid "Pid %d is stale, relaunching dnsmasq"
msgstr ""
-#. pylint: disable-msg=W0703
+#. pylint: disable=W0703
#: ../nova/network/linux_net.py:358
#, python-format
msgid "killing radvd threw %s"
@@ -613,7 +613,7 @@ msgstr ""
msgid "Pid %d is stale, relaunching radvd"
msgstr ""
-#. pylint: disable-msg=W0703
+#. pylint: disable=W0703
#: ../nova/network/linux_net.py:449
#, python-format
msgid "Killing dnsmasq threw %s"
diff --git a/tools/euca-get-ajax-console b/tools/euca-get-ajax-console
index e407dd566..3df3dcb53 100755
--- a/tools/euca-get-ajax-console
+++ b/tools/euca-get-ajax-console
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# pylint: disable-msg=C0103
+# pylint: disable=C0103
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
--
cgit
From 204ec967ee46079fb95a18fcfb1167ff57458015 Mon Sep 17 00:00:00 2001
From: Brian Lamar
Date: Fri, 18 Mar 2011 09:56:38 -0400
Subject: enable-msg -> enable
---
nova/auth/fakeldap.py | 2 +-
nova/tests/objectstore_unittest.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/nova/auth/fakeldap.py b/nova/auth/fakeldap.py
index e8f5771d5..79afb9109 100644
--- a/nova/auth/fakeldap.py
+++ b/nova/auth/fakeldap.py
@@ -277,7 +277,7 @@ class FakeLDAP(object):
attrs = dict([(k, v) for k, v in attrs.iteritems()
if not fields or k in fields])
objects.append((key[len(self.__prefix):], attrs))
- # pylint: enable-msg=E1103
+ # pylint: enable=E1103
if objects == []:
raise NO_SUCH_OBJECT()
return objects
diff --git a/nova/tests/objectstore_unittest.py b/nova/tests/objectstore_unittest.py
index 5d160bdf8..4e2ac205e 100644
--- a/nova/tests/objectstore_unittest.py
+++ b/nova/tests/objectstore_unittest.py
@@ -212,7 +212,7 @@ class S3APITestCase(test.TestCase):
# pylint: disable=E1101
self.listening_port = reactor.listenTCP(0, self.site,
interface='127.0.0.1')
- # pylint: enable-msg=E1101
+ # pylint: enable=E1101
self.tcp_port = self.listening_port.getHost().port
if not boto.config.has_section('Boto'):
--
cgit
From a50deeb264ff721584d5b0a6ace749d8e2c44842 Mon Sep 17 00:00:00 2001
From: Dan Prince
Date: Fri, 18 Mar 2011 10:10:46 -0400
Subject: Change cloud.id_to_ec2_id to ec2utils.id_to_ec2_id. Fixes EC2 API
error handling when invalid instances and volume names are specified.
---
nova/api/ec2/__init__.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py
index fccebca5d..20701cfa8 100644
--- a/nova/api/ec2/__init__.py
+++ b/nova/api/ec2/__init__.py
@@ -31,7 +31,7 @@ from nova import log as logging
from nova import utils
from nova import wsgi
from nova.api.ec2 import apirequest
-from nova.api.ec2 import cloud
+from nova.api.ec2 import ec2utils
from nova.auth import manager
@@ -319,13 +319,13 @@ class Executor(wsgi.Application):
except exception.InstanceNotFound as ex:
LOG.info(_('InstanceNotFound raised: %s'), unicode(ex),
context=context)
- ec2_id = cloud.id_to_ec2_id(ex.instance_id)
+ ec2_id = ec2utils.id_to_ec2_id(ex.instance_id)
message = _('Instance %s not found') % ec2_id
return self._error(req, context, type(ex).__name__, message)
except exception.VolumeNotFound as ex:
LOG.info(_('VolumeNotFound raised: %s'), unicode(ex),
context=context)
- ec2_id = cloud.id_to_ec2_id(ex.volume_id, 'vol-%08x')
+ ec2_id = ec2utils.id_to_ec2_id(ex.volume_id, 'vol-%08x')
message = _('Volume %s not found') % ec2_id
return self._error(req, context, type(ex).__name__, message)
except exception.NotFound as ex:
--
cgit
From dba79cdf18f20f1e4e0758ae19b33de94881e440 Mon Sep 17 00:00:00 2001
From: Dan Prince
Date: Fri, 18 Mar 2011 11:12:44 -0400
Subject: Added test case.
---
nova/tests/test_api.py | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py
index d5c54a1c3..7023eb410 100644
--- a/nova/tests/test_api.py
+++ b/nova/tests/test_api.py
@@ -20,6 +20,7 @@
import boto
from boto.ec2 import regioninfo
+from boto.exception import EC2ResponseError
import datetime
import httplib
import random
@@ -177,6 +178,17 @@ class ApiEc2TestCase(test.TestCase):
self.manager.delete_project(project)
self.manager.delete_user(user)
+ def test_terminate_invalid_instance(self):
+ """Attempt to terminate an invalid instance"""
+ self.expect_http()
+ self.mox.ReplayAll()
+ user = self.manager.create_user('fake', 'fake', 'fake')
+ project = self.manager.create_project('fake', 'fake', 'fake')
+ self.assertRaises(EC2ResponseError, self.ec2.terminate_instances,
+ "i-00000005")
+ self.manager.delete_project(project)
+ self.manager.delete_user(user)
+
def test_get_all_key_pairs(self):
"""Test that, after creating a user and project and generating
a key pair, that the API call to list key pairs works properly"""
--
cgit
From 4f5dc6314f9dd7bb136a38fa07b109eb2e12734d Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Fri, 18 Mar 2011 10:06:36 -0700
Subject: auth_data is a list now (thanks Rick!)
---
nova/tests/api/openstack/fakes.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py
index 5decb2bad..020682093 100644
--- a/nova/tests/api/openstack/fakes.py
+++ b/nova/tests/api/openstack/fakes.py
@@ -240,7 +240,8 @@ class FakeAuthManager(object):
@classmethod
def reset_fake_data(cls):
- cls.auth_data = dict(u1=User('id1', 'guy1', 'acc1', 'secret1', False))
+ u1 = User('id1', 'guy1', 'acc1', 'secret1', False)
+ cls.auth_data = [u1]
cls.projects = dict(testacct=Project('testacct',
'testacct',
'id1',
--
cgit
From ee09125e31a3afe64f0a9540a88fdb5febd7ddd4 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Fri, 18 Mar 2011 10:14:42 -0700
Subject: Avoid single-letter variable names
---
nova/tests/api/openstack/fakes.py | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py
index 020682093..9b5ed8a15 100644
--- a/nova/tests/api/openstack/fakes.py
+++ b/nova/tests/api/openstack/fakes.py
@@ -255,21 +255,21 @@ class FakeAuthManager(object):
return FakeAuthManager.auth_data
def get_user(self, uid):
- for u in FakeAuthManager.auth_data:
- if u.id == uid:
- return u
+ for user in FakeAuthManager.auth_data:
+ if user.id == uid:
+ return user
return None
def get_user_from_access_key(self, key):
- for u in FakeAuthManager.auth_data:
- if u.access == key:
- return u
+ for user in FakeAuthManager.auth_data:
+ if user.access == key:
+ return user
return None
def delete_user(self, uid):
- for u in FakeAuthManager.auth_data:
- if u.id == uid:
- FakeAuthManager.auth_data.remove(u)
+ for user in FakeAuthManager.auth_data:
+ if user.id == uid:
+ FakeAuthManager.auth_data.remove(user)
return None
def create_user(self, name, access=None, secret=None, admin=False):
@@ -278,10 +278,7 @@ class FakeAuthManager(object):
return u
def modify_user(self, user_id, access=None, secret=None, admin=None):
- user = None
- for u in FakeAuthManager.auth_data:
- if u.id == user_id:
- user = u
+ user = self.get_user(user_id)
if user:
user.access = access
user.secret = secret
--
cgit
From 48a1423081355b49340aa1a4a37361654d9c0d87 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Fri, 18 Mar 2011 10:24:06 -0700
Subject: A few more single-letter variable names bite the dust
---
nova/tests/api/openstack/test_auth.py | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/nova/tests/api/openstack/test_auth.py b/nova/tests/api/openstack/test_auth.py
index 446c5c149..21596fb25 100644
--- a/nova/tests/api/openstack/test_auth.py
+++ b/nova/tests/api/openstack/test_auth.py
@@ -51,8 +51,8 @@ class Test(test.TestCase):
def test_authorize_user(self):
f = fakes.FakeAuthManager()
- u = nova.auth.manager.User('id1', 'user1', 'user1_key', None, None)
- f.add_user(u)
+ user = nova.auth.manager.User('id1', 'user1', 'user1_key', None, None)
+ f.add_user(user)
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-User'] = 'user1'
@@ -66,9 +66,9 @@ class Test(test.TestCase):
def test_authorize_token(self):
f = fakes.FakeAuthManager()
- u = nova.auth.manager.User('id1', 'user1', 'user1_key', None, None)
- f.add_user(u)
- f.create_project('user1_project', u)
+ user = nova.auth.manager.User('id1', 'user1', 'user1_key', None, None)
+ f.add_user(user)
+ f.create_project('user1_project', user)
req = webob.Request.blank('/v1.0/', {'HTTP_HOST': 'foo'})
req.headers['X-Auth-User'] = 'user1'
@@ -124,8 +124,8 @@ class Test(test.TestCase):
def test_bad_user_good_key(self):
f = fakes.FakeAuthManager()
- u = nova.auth.manager.User('id1', 'user1', 'user1_key', None, None)
- f.add_user(u)
+ user = nova.auth.manager.User('id1', 'user1', 'user1_key', None, None)
+ f.add_user(user)
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-User'] = 'unknown_user'
@@ -190,9 +190,9 @@ class TestLimiter(test.TestCase):
def test_authorize_token(self):
f = fakes.FakeAuthManager()
- u = nova.auth.manager.User('id1', 'user1', 'user1_key', None, None)
- f.add_user(u)
- f.create_project('test', u)
+ user = nova.auth.manager.User('id1', 'user1', 'user1_key', None, None)
+ f.add_user(user)
+ f.create_project('test', user)
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-User'] = 'user1'
--
cgit
From a0052203c7cc957677293e53ea7c0191d0493ea8 Mon Sep 17 00:00:00 2001
From: Ken Pepple
Date: Fri, 18 Mar 2011 12:18:15 -0700
Subject: uses True/False instead of 1/0 for Postgres compatibility
---
nova/db/api.py | 2 +-
nova/db/sqlalchemy/api.py | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/nova/db/api.py b/nova/db/api.py
index 3cb0e5811..dd78fa3e7 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -1118,7 +1118,7 @@ def instance_type_create(context, values):
return IMPL.instance_type_create(context, values)
-def instance_type_get_all(context, inactive=0):
+def instance_type_get_all(context, inactive=False):
"""Get all instance types"""
return IMPL.instance_type_get_all(context, inactive)
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 9d9b86c1d..e72be0e0c 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -2337,7 +2337,7 @@ def instance_type_create(_context, values):
@require_context
-def instance_type_get_all(context, inactive=0):
+def instance_type_get_all(context, inactive=False):
"""
Returns a dict describing all instance_types with name as key.
"""
@@ -2392,7 +2392,7 @@ def instance_type_destroy(context, name):
session = get_session()
instance_type_ref = session.query(models.InstanceTypes).\
filter_by(name=name)
- records = instance_type_ref.update(dict(deleted=1))
+ records = instance_type_ref.update(dict(deleted=True))
if records == 0:
raise exception.NotFound
else:
--
cgit
From 8437d947a6e94baf7aa53746ffd34aa5c0f521d9 Mon Sep 17 00:00:00 2001
From: Josh Kearney
Date: Fri, 18 Mar 2011 15:34:50 -0500
Subject: Better errors when virt driver isn't loaded
---
nova/compute/manager.py | 12 ++++++++++--
plugins/xenserver/xenapi/etc/xapi.d/plugins/glance | 3 +--
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 92deca813..5b8e4dafb 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -39,6 +39,7 @@ import os
import random
import string
import socket
+import sys
import tempfile
import time
import functools
@@ -114,7 +115,13 @@ class ComputeManager(manager.Manager):
# and redocument the module docstring
if not compute_driver:
compute_driver = FLAGS.compute_driver
- self.driver = utils.import_object(compute_driver)
+
+ try:
+ self.driver = utils.import_object(compute_driver)
+ except ImportError:
+ LOG.error("Unable to load the virtualization driver.")
+ sys.exit(1)
+
self.network_manager = utils.import_object(FLAGS.network_manager)
self.volume_manager = utils.import_object(FLAGS.volume_manager)
super(ComputeManager, self).__init__(*args, **kwargs)
@@ -221,7 +228,8 @@ class ComputeManager(manager.Manager):
instance_id,
{'launched_at': now})
except Exception: # pylint: disable-msg=W0702
- LOG.exception(_("instance %s: Failed to spawn"), instance_id,
+ LOG.exception(_("Instance '%s' failed to spawn. Is virtualization"
+ "enabled in the BIOS?"), instance_id,
context=context)
self.db.instance_set_state(context,
instance_id,
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance
index c996f6ef4..0a45f3873 100644
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance
@@ -216,8 +216,7 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type):
'x-image-meta-status': 'queued',
'x-image-meta-disk-format': 'vhd',
'x-image-meta-container-format': 'ovf',
- 'x-image-meta-property-os-type': os_type
- }
+ 'x-image-meta-property-os-type': os_type}
for header, value in headers.iteritems():
conn.putheader(header, value)
--
cgit
From d6589138bd06e19851594e62fc515b964596bf61 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Fri, 18 Mar 2011 14:34:37 -0700
Subject: Fixed netadmin smoketests for ipv6
---
contrib/boto_v6/ec2/connection.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/contrib/boto_v6/ec2/connection.py b/contrib/boto_v6/ec2/connection.py
index faecae95e..868c93c11 100644
--- a/contrib/boto_v6/ec2/connection.py
+++ b/contrib/boto_v6/ec2/connection.py
@@ -4,8 +4,10 @@ Created on 2010/12/20
@author: Nachi Ueno
'''
import boto
+import base64
import boto.ec2
from boto_v6.ec2.instance import ReservationV6
+from boto.ec2.securitygroup import SecurityGroup
class EC2ConnectionV6(boto.ec2.EC2Connection):
@@ -101,7 +103,7 @@ class EC2ConnectionV6(boto.ec2.EC2Connection):
with the Image.
:rtype: Reservation
- :return: The :class:`boto.ec2.instance.Reservation`
+ :return: The :class:`boto.ec2.instance.ReservationV6`
associated with the request for machines
"""
params = {'ImageId': image_id,
--
cgit
From ac66fde6d787742e9d5d6af9ebfe3302d9375073 Mon Sep 17 00:00:00 2001
From: Trey Morris
Date: Fri, 18 Mar 2011 17:22:13 -0500
Subject: comment more descriptive
---
nova/virt/xenapi/vmops.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 6542630c1..cfd74e5de 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -734,7 +734,7 @@ class VMOps(object):
"""
logging.debug(_("injecting network info to xs for vm: |%s|"), vm_ref)
- # make sure we have a vm opaque ref (raises otherwise)
+ # this function raises if vm_ref is not a vm_opaque_ref
self._session.get_xenapi().VM.get_record(vm_ref)
for (network, info) in network_info:
@@ -754,7 +754,7 @@ class VMOps(object):
"""Creates vifs for an instance"""
logging.debug(_("creating vif(s) for vm: |%s|"), vm_ref)
- # make sure we have a vm opaque ref (raises otherwise)
+ # this function raises if vm_ref is not a vm_opaque_ref
self._session.get_xenapi().VM.get_record(vm_ref)
device = 0
--
cgit
From 3113a9c523a37c777164b7d1216e1df61bd3f825 Mon Sep 17 00:00:00 2001
From: Ken Pepple
Date: Fri, 18 Mar 2011 16:28:53 -0700
Subject: fixed migration instance_types migration to support postgres
correctly
---
nova/db/sqlalchemy/migrate_repo/versions/008_add_instance_types.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/008_add_instance_types.py b/nova/db/sqlalchemy/migrate_repo/versions/008_add_instance_types.py
index 66609054e..5e2cb69d9 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/008_add_instance_types.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/008_add_instance_types.py
@@ -55,7 +55,7 @@ def upgrade(migrate_engine):
try:
instance_types.create()
except Exception:
- logging.info(repr(table))
+ logging.info(repr(instance_types))
logging.exception('Exception while creating instance_types table')
raise
@@ -72,11 +72,11 @@ def upgrade(migrate_engine):
# FIXME(kpepple) should we be seeding created_at / updated_at ?
# now = datetime.datatime.utcnow()
i.execute({'name': name, 'memory_mb': values["memory_mb"],
- 'vcpus': values["vcpus"], 'deleted': 0,
+ 'vcpus': values["vcpus"], 'deleted': False,
'local_gb': values["local_gb"],
'flavorid': values["flavorid"]})
except Exception:
- logging.info(repr(table))
+ logging.info(repr(instance_types))
logging.exception('Exception while seeding instance_types table')
raise
--
cgit
From 157b4d67ae2cfb7cda6cf145a5803ff83b848075 Mon Sep 17 00:00:00 2001
From: Ken Pepple
Date: Fri, 18 Mar 2011 16:50:08 -0700
Subject: fix nova-manage instance_type list for postgres compatibility
---
nova/db/sqlalchemy/api.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 5430f89f9..3bf4f5eb8 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -2353,7 +2353,7 @@ def instance_type_get_all(context, inactive=False):
all()
else:
inst_types = session.query(models.InstanceTypes).\
- filter_by(deleted=inactive).\
+ filter_by(deleted=False).\
order_by("name").\
all()
if inst_types:
--
cgit
From a3fe673108602e27cca132209e87369fa8bf1323 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Fri, 18 Mar 2011 19:46:04 -0700
Subject: Changed Copyright to NTT for newly added files for flatmanager ipv6
---
.../versions/012_add_ipv6_flatmanager.py | 2 +-
nova/tests/network/__init__.py | 20 ++++++++++++++++++++
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
index 5f5e3d007..8c9cf3377 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
@@ -1,4 +1,4 @@
-# Copyright 2010 OpenStack LLC.
+# Copyright (c) 2011 NTT.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
diff --git a/nova/tests/network/__init__.py b/nova/tests/network/__init__.py
index e0d479f8c..97f96b6fa 100644
--- a/nova/tests/network/__init__.py
+++ b/nova/tests/network/__init__.py
@@ -1,3 +1,23 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# 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.
+"""
+Utility methods
+"""
import os
from nova import context
--
cgit
From bdbdc3fc49e3885df6dbfe75badab35f5fd15c8d Mon Sep 17 00:00:00 2001
From: Ken Pepple
Date: Fri, 18 Mar 2011 23:10:14 -0700
Subject: cleanup another inconsistent use of 1 for True in nova-manage
---
bin/nova-manage | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bin/nova-manage b/bin/nova-manage
index 6dcdddd5e..013a6077b 100755
--- a/bin/nova-manage
+++ b/bin/nova-manage
@@ -874,7 +874,7 @@ class InstanceTypeCommands(object):
if name == None:
inst_types = instance_types.get_all_types()
elif name == "--all":
- inst_types = instance_types.get_all_types(1)
+ inst_types = instance_types.get_all_types(True)
else:
inst_types = instance_types.get_instance_type(name)
except exception.DBError, e:
--
cgit
From 98b0fd564ca86a7b38bca149b28a837c8aa2d1e8 Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Sun, 20 Mar 2011 20:06:22 +0100
Subject: pep8
---
nova/tests/api/openstack/test_servers.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py
index bb33ec03d..efba2970f 100644
--- a/nova/tests/api/openstack/test_servers.py
+++ b/nova/tests/api/openstack/test_servers.py
@@ -1174,5 +1174,3 @@ class TestServerInstanceCreation(test.TestCase):
server = dom.childNodes[0]
self.assertEquals(server.nodeName, 'server')
self.assertTrue(server.getAttribute('adminPass').startswith('fake'))
-
-
--
cgit
From 9192e80d1161814e7b14946a5bd5787e9a8cf31d Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Mon, 21 Mar 2011 09:49:32 +0100
Subject: Wrap update_dhcp in utils.synchronized.
---
nova/network/linux_net.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index 565732869..ee36407a6 100644
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -557,6 +557,7 @@ def get_dhcp_hosts(context, network_id):
# NOTE(ja): Sending a HUP only reloads the hostfile, so any
# configuration options (like dchp-range, vlan, ...)
# aren't reloaded.
+@utils.synchronized('dnsmasq_start')
def update_dhcp(context, network_id):
"""(Re)starts a dnsmasq server for a given network
--
cgit
--
cgit
From 665e155339b8c4498e39e783710d869dcfc94238 Mon Sep 17 00:00:00 2001
From: Josh Kleinpeter
Date: Mon, 21 Mar 2011 09:06:42 -0500
Subject: Added my name to Authors Added I18n for network create string
---
Authors | 1 +
bin/nova-manage | 4 ++--
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/Authors b/Authors
index 9aad104a7..1679d2dee 100644
--- a/Authors
+++ b/Authors
@@ -33,6 +33,7 @@ Jonathan Bryce
Jordan Rinke
Josh Durgin
Josh Kearney
+Josh Kleinpeter
Joshua McKenty
Justin Santa Barbara
Kei Masumoto
diff --git a/bin/nova-manage b/bin/nova-manage
index 0c39b662c..53e954003 100755
--- a/bin/nova-manage
+++ b/bin/nova-manage
@@ -522,8 +522,8 @@ class NetworkCommands(object):
[network_size=FLAG], [vlan_start=FLAG],
[vpn_start=FLAG], [fixed_range_v6=FLAG]"""
if not fixed_range:
- raise ValueError('Fixed range in the form of 10.0.0.0/8 is '
- 'required to create networks.')
+ raise ValueError(_('Fixed range in the form of 10.0.0.0/8 is '
+ 'required to create networks.'))
if not num_networks:
num_networks = FLAGS.num_networks
if not network_size:
--
cgit
From 3754a7b6f4cf0e9c60a140348b4cdb9c8acde062 Mon Sep 17 00:00:00 2001
From: Josh Kleinpeter
Date: Mon, 21 Mar 2011 09:17:12 -0500
Subject: Changed error to TypeError so that we get the arguments list.
---
bin/nova-manage | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/bin/nova-manage b/bin/nova-manage
index 53e954003..bdc129077 100755
--- a/bin/nova-manage
+++ b/bin/nova-manage
@@ -522,8 +522,8 @@ class NetworkCommands(object):
[network_size=FLAG], [vlan_start=FLAG],
[vpn_start=FLAG], [fixed_range_v6=FLAG]"""
if not fixed_range:
- raise ValueError(_('Fixed range in the form of 10.0.0.0/8 is '
- 'required to create networks.'))
+ raise TypeError(_('Fixed range in the form of 10.0.0.0/8 is '
+ 'required to create networks.'))
if not num_networks:
num_networks = FLAGS.num_networks
if not network_size:
--
cgit
From b3bb847e3dc20611c4a975d3c772256700b2d018 Mon Sep 17 00:00:00 2001
From: Josh Kearney
Date: Mon, 21 Mar 2011 10:41:03 -0500
Subject: Added space
---
nova/compute/manager.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index ff33597ce..576937cd8 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -229,7 +229,7 @@ class ComputeManager(manager.Manager):
{'launched_at': now})
except Exception: # pylint: disable=W0702
LOG.exception(_("Instance '%s' failed to spawn. Is virtualization"
- "enabled in the BIOS?"), instance_id,
+ " enabled in the BIOS?"), instance_id,
context=context)
self.db.instance_set_state(context,
instance_id,
--
cgit
From 6a893eabc83f4561025a9a655b0aabb2d3e1b3a7 Mon Sep 17 00:00:00 2001
From: Trey Morris
Date: Mon, 21 Mar 2011 13:19:20 -0500
Subject: added an enumerate to track device in vmops.create_vifs()
---
nova/virt/xenapi/vmops.py | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index cfd74e5de..61ff00903 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -757,8 +757,7 @@ class VMOps(object):
# this function raises if vm_ref is not a vm_opaque_ref
self._session.get_xenapi().VM.get_record(vm_ref)
- device = 0
- for (network, info) in network_info:
+ for device, (network, info) in enumerate(network_info):
mac_address = info['mac']
bridge = network['bridge']
rxtx_cap = info.pop('rxtx_cap')
@@ -767,7 +766,6 @@ class VMOps(object):
VMHelper.create_vif(self._session, vm_ref, network_ref,
mac_address, device, rxtx_cap)
- device += 1
def reset_network(self, instance, vm_ref):
"""Creates uuid arg to pass to make_agent_call and calls it."""
--
cgit
From 0cff0a13bac3539a46b3b932bfd016df7f190196 Mon Sep 17 00:00:00 2001
From: Vishvananda Ishaya
Date: Mon, 21 Mar 2011 14:20:13 -0700
Subject: import greenthread in libvirt
---
nova/virt/libvirt_conn.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index e80b9fbdf..f57f1a675 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -46,10 +46,9 @@ import time
import uuid
from xml.dom import minidom
-
+from eventlet import greenthread
from eventlet import tpool
from eventlet import semaphore
-
import IPy
from nova import context
--
cgit
From 4b8ed5afd1fd3e616eda0015f9bf16c7097f5476 Mon Sep 17 00:00:00 2001
From: Todd Willey
Date: Tue, 22 Mar 2011 03:13:12 -0400
Subject: vpn changes
---
nova/api/ec2/admin.py | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py
index d9a4ef999..208fe5c4f 100644
--- a/nova/api/ec2/admin.py
+++ b/nova/api/ec2/admin.py
@@ -28,6 +28,7 @@ from nova import exception
from nova import flags
from nova import log as logging
from nova import utils
+from nova.api.ec2 import ec2utils
from nova.auth import manager
@@ -92,15 +93,18 @@ def vpn_dict(project, vpn_instance):
'public_ip': project.vpn_ip,
'public_port': project.vpn_port}
if vpn_instance:
- rv['instance_id'] = vpn_instance['ec2_id']
+ rv['instance_id'] = ec2utils.id_to_ec2_id(vpn_instance['id'])
rv['created_at'] = utils.isotime(vpn_instance['created_at'])
address = vpn_instance.get('fixed_ip', None)
if address:
rv['internal_ip'] = address['address']
- if utils.vpn_ping(project.vpn_ip, project.vpn_port):
- rv['state'] = 'running'
+ if project.vpn_ip and project.vpn_port:
+ if utils.vpn_ping(project.vpn_ip, project.vpn_port):
+ rv['state'] = 'running'
+ else:
+ rv['state'] = 'down'
else:
- rv['state'] = 'down'
+ rv['state'] = 'down - invalid project vpn config'
else:
rv['state'] = 'pending'
return rv
@@ -279,7 +283,7 @@ class AdminController(object):
", ensure it isn't running, and try "
"again in a few minutes")
instance = self._vpn_for(context, project)
- return {'instance_id': instance['ec2_id']}
+ return {'instance_id': ec2utils.id_to_ec2_id(instance['id'])}
def describe_vpns(self, context):
vpns = []
--
cgit
From e827b8dbae1faef2cc070c7e26395979571bcd46 Mon Sep 17 00:00:00 2001
From: Hisaharu Ishii
Date: Tue, 22 Mar 2011 20:27:51 +0900
Subject: Wrap update_ra in utils.synchronized.
---
nova/network/linux_net.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index ee36407a6..e283dee37 100644
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -595,6 +595,7 @@ def update_dhcp(context, network_id):
_execute(*command, addl_env=env)
+@utils.synchronized('radvd_start')
def update_ra(context, network_id):
network_ref = db.network_get(context, network_id)
--
cgit
From d06bce4b64b57551a722688a4038a4eaffa34278 Mon Sep 17 00:00:00 2001
From: Todd Willey
Date: Tue, 22 Mar 2011 16:34:02 -0400
Subject: typo fix.
---
nova/api/ec2/admin.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py
index d9a4ef999..f32d0804f 100644
--- a/nova/api/ec2/admin.py
+++ b/nova/api/ec2/admin.py
@@ -60,7 +60,7 @@ def project_dict(project):
def host_dict(host, compute_service, instances, volume_service, volumes, now):
"""Convert a host model object to a result dict"""
- rv = {'hostanme': host, 'instance_count': len(instances),
+ rv = {'hostname': host, 'instance_count': len(instances),
'volume_count': len(volumes)}
if compute_service:
latest = compute_service['updated_at'] or compute_service['created_at']
--
cgit
From 0dc2140d645d94d585fa8e3e5d189cd776574d28 Mon Sep 17 00:00:00 2001
From: Koji Iida
Date: Wed, 23 Mar 2011 13:14:54 +0900
Subject: Fix to avoid db migration failure in virtualenv
---
nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
index 8c9cf3377..e87085668 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
@@ -26,6 +26,9 @@ meta = MetaData()
# Just for the ForeignKey and column creation to succeed, these are not the
# actual definitions of instances or services.
#
+instances = Table('instances', meta,
+ Column('id', Integer(), primary_key=True, nullable=False),
+ )
#
# Tables to alter
--
cgit
From 846b09925da07c2858052143d5fff4766a782cf1 Mon Sep 17 00:00:00 2001
From: Anthony Young
Date: Tue, 22 Mar 2011 22:54:34 -0700
Subject: Fix for lp740742 - format describe_instance_output correctly to
prevent errors in dashboard
---
nova/api/ec2/admin.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py
index 037184b40..d8d90ad83 100644
--- a/nova/api/ec2/admin.py
+++ b/nova/api/ec2/admin.py
@@ -120,7 +120,8 @@ class AdminController(object):
def describe_instance_types(self, context, **_kwargs):
"""Returns all active instance types data (vcpus, memory, etc.)"""
- return {'instanceTypeSet': [db.instance_type_get_all(context)]}
+ return {'instanceTypeSet': [instance_dict(v) for v in
+ db.instance_type_get_all(context).values()]}
def describe_user(self, _context, name, **_kwargs):
"""Returns user data, including access and secret keys."""
--
cgit