From a7e1a322ef0c8d78af4d1b0c5719bc506214f49d Mon Sep 17 00:00:00 2001 From: Ed Leafe Date: Tue, 21 Dec 2010 14:17:29 -0600 Subject: [PATCH 01/31] Refactored duplicate rpc.cast() calls in nova/compute/api.py. Cleaned up some formatting issues. --- nova/tests/compute_unittest.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/nova/tests/compute_unittest.py b/nova/tests/compute_unittest.py index 187ca31de..16e577c56 100644 --- a/nova/tests/compute_unittest.py +++ b/nova/tests/compute_unittest.py @@ -142,6 +142,13 @@ class ComputeTestCase(test.TestCase): self.compute.reboot_instance(self.context, instance_id) self.compute.terminate_instance(self.context, instance_id) + def test_reset_root_password(self): + """Ensure instance can have its root password reset""" + instance_id = self._create_instance() + self.compute.run_instance(self.context, instance_id) + self.compute.reset_root_password(self.context, instance_id) + self.compute.terminate_instance(self.context, instance_id) + def test_console_output(self): """Make sure we can get console output from instance""" instance_id = self._create_instance() From 9f4034526185037d53456f6f11c0b0cb84d77b04 Mon Sep 17 00:00:00 2001 From: Andy Smith Date: Wed, 22 Dec 2010 16:43:47 -0800 Subject: [PATCH 02/31] Basic Easy API functionality --- nova/tests/easy_unittest.py | 85 +++++++++++++++++++++++++++++++++++++ nova/wsgi.py | 31 +++++++++++--- run_tests.py | 1 + 3 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 nova/tests/easy_unittest.py diff --git a/nova/tests/easy_unittest.py b/nova/tests/easy_unittest.py new file mode 100644 index 000000000..ed223831f --- /dev/null +++ b/nova/tests/easy_unittest.py @@ -0,0 +1,85 @@ +# 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. + +"""Tests for Easy API.""" + +import json +import logging + +import webob + +from nova import context +from nova import exception +from nova import test +from nova import utils +from nova.api import easy + + +class FakeService(object): + def echo(self, context, data): + return {'data': data} + + def context(self, context): + return {'user': context.user_id, + 'project': context.project_id} + + +class EasyTestCase(test.TestCase): + def setUp(self): + super(EasyTestCase, self).setUp() + easy.register_service('fake', FakeService()) + self.router = easy.ReqParamsMiddleware( + easy.JsonParamsMiddleware( + easy.SundayMorning())) + self.auth_router = easy.DelegatedAuthMiddleware(self.router) + self.context = context.RequestContext('user1', 'proj1') + + def tearDown(self): + easy.EASY_ROUTES = {} + + def test_delegated_auth(self): + req = webob.Request.blank('/fake/context') + req.headers['X-OpenStack-User'] = 'user1' + req.headers['X-OpenStack-Project'] = 'proj1' + resp = req.get_response(self.auth_router) + data = json.loads(resp.body) + self.assertEqual(data['user'], 'user1') + self.assertEqual(data['project'], 'proj1') + + def test_json_params(self): + req = webob.Request.blank('/fake/echo') + req.environ['openstack.context'] = self.context + req.method = 'POST' + req.body = 'json=%s' % json.dumps({'data': 'foo'}) + resp = req.get_response(self.router) + resp_parsed = json.loads(resp.body) + self.assertEqual(resp_parsed['data'], 'foo') + + def test_req_params(self): + req = webob.Request.blank('/fake/echo') + req.environ['openstack.context'] = self.context + req.method = 'POST' + req.body = 'data=foo' + resp = req.get_response(self.router) + resp_parsed = json.loads(resp.body) + self.assertEqual(resp_parsed['data'], 'foo') + + def test_proxy(self): + proxy = easy.Proxy(self.router) + rv = proxy.fake.echo(self.context, data='baz') + self.assertEqual(rv['data'], 'baz') diff --git a/nova/wsgi.py b/nova/wsgi.py index c7ee9ed14..2ad27dd7e 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -104,20 +104,39 @@ class Application(object): class Middleware(Application): - """ - Base WSGI middleware wrapper. These classes require an application to be + """Base WSGI middleware. + + Modelled after Django's middleware this class allows you to + These classes require an application to be initialized that will be called next. By default the middleware will simply call its wrapped app, or you can override __call__ to customize its behavior. """ - def __init__(self, application): # pylint: disable-msg=W0231 + def __init__(self, application): self.application = application + def process_request(self, req): + """Called on each request. + + If this returns None, the next application down the stack will be + executed. If it returns a response then that response will be returned + and execution will stop here. + + """ + return None + + def process_response(self, response): + """Do whatever you'd like to the response.""" + return response + @webob.dec.wsgify - def __call__(self, req): # pylint: disable-msg=W0221 - """Override to implement middleware behavior.""" - return self.application + def __call__(self, req): + response = self.process_request(req) + if response: + return response + response = req.get_response(self.application) + return self.process_response(response) class Debug(Middleware): diff --git a/run_tests.py b/run_tests.py index 6a4b7f1ab..d3cf8f696 100644 --- a/run_tests.py +++ b/run_tests.py @@ -59,6 +59,7 @@ from nova.tests.api_unittest import * from nova.tests.auth_unittest import * from nova.tests.cloud_unittest import * from nova.tests.compute_unittest import * +from nova.tests.easy_unittest import * from nova.tests.flags_unittest import * from nova.tests.misc_unittest import * from nova.tests.network_unittest import * From 85204f0a222bf5db23549d7ad9ab3289a185b5f3 Mon Sep 17 00:00:00 2001 From: Andy Smith Date: Wed, 22 Dec 2010 16:52:16 -0800 Subject: [PATCH 03/31] remove some yields that snuck in --- nova/tests/cloud_unittest.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nova/tests/cloud_unittest.py b/nova/tests/cloud_unittest.py index 70d2c44da..1398a9862 100644 --- a/nova/tests/cloud_unittest.py +++ b/nova/tests/cloud_unittest.py @@ -140,15 +140,15 @@ class CloudTestCase(test.TestCase): kwargs = {'image_id': image_id, 'instance_type': instance_type, 'max_count': max_count} - rv = yield self.cloud.run_instances(self.context, **kwargs) + rv = self.cloud.run_instances(self.context, **kwargs) instance_id = rv['instancesSet'][0]['instanceId'] - output = yield self.cloud.get_console_output(context=self.context, + output = self.cloud.get_console_output(context=self.context, instance_id=[instance_id]) self.assertEquals(b64decode(output['output']), 'FAKE CONSOLE OUTPUT') # TODO(soren): We need this until we can stop polling in the rpc code # for unit tests. greenthread.sleep(0.3) - rv = yield self.cloud.terminate_instances(self.context, [instance_id]) + rv = self.cloud.terminate_instances(self.context, [instance_id]) def test_key_generation(self): result = self._create_key('test') @@ -186,7 +186,7 @@ class CloudTestCase(test.TestCase): kwargs = {'image_id': image_id, 'instance_type': instance_type, 'max_count': max_count} - rv = yield self.cloud.run_instances(self.context, **kwargs) + rv = self.cloud.run_instances(self.context, **kwargs) # TODO: check for proper response instance_id = rv['reservationSet'][0].keys()[0] instance = rv['reservationSet'][0][instance_id][0] @@ -209,7 +209,7 @@ class CloudTestCase(test.TestCase): for instance in reservations[reservations.keys()[0]]: instance_id = instance['instance_id'] logging.debug("Terminating instance %s" % instance_id) - rv = yield self.compute.terminate_instance(instance_id) + rv = self.compute.terminate_instance(instance_id) def test_instance_update_state(self): def instance(num): From f9f0b6e384c1def8dcec8c71c5bfbd2894693576 Mon Sep 17 00:00:00 2001 From: Andy Smith Date: Wed, 22 Dec 2010 17:53:42 -0800 Subject: [PATCH 04/31] added tests to ensure the easy api works as a backend for Compute API --- nova/tests/cloud_unittest.py | 2 ++ nova/tests/compute_unittest.py | 9 ++++++--- nova/tests/easy_unittest.py | 19 ++++++++++++++++++- nova/utils.py | 31 +++++++++++++++++++++++++++++++ nova/wsgi.py | 6 +++--- 5 files changed, 60 insertions(+), 7 deletions(-) diff --git a/nova/tests/cloud_unittest.py b/nova/tests/cloud_unittest.py index 1398a9862..4439c131c 100644 --- a/nova/tests/cloud_unittest.py +++ b/nova/tests/cloud_unittest.py @@ -22,6 +22,7 @@ import logging from M2Crypto import BIO from M2Crypto import RSA import os +import shutil import tempfile import time @@ -293,6 +294,7 @@ class CloudTestCase(test.TestCase): self.assertEqual('Foo Img', img.metadata['description']) self._fake_set_image_description(self.context, 'ami-testing', '') self.assertEqual('', img.metadata['description']) + shutil.rmtree(pathdir) def test_update_of_instance_display_fields(self): inst = db.instance_create(self.context, {}) diff --git a/nova/tests/compute_unittest.py b/nova/tests/compute_unittest.py index 348bb3351..0bebd1c5e 100644 --- a/nova/tests/compute_unittest.py +++ b/nova/tests/compute_unittest.py @@ -75,7 +75,7 @@ class ComputeTestCase(test.TestCase): ref = self.compute_api.create_instances(self.context, FLAGS.default_instance_type, None, **instance) try: - self.assertNotEqual(ref[0].display_name, None) + self.assertNotEqual(ref[0]['display_name'], None) finally: db.instance_destroy(self.context, ref[0]['id']) @@ -87,9 +87,12 @@ class ComputeTestCase(test.TestCase): 'project_id': self.project.id} group = db.security_group_create(self.context, values) ref = self.compute_api.create_instances(self.context, - FLAGS.default_instance_type, None, security_group=['default']) + instance_type=FLAGS.default_instance_type, + image_id=None, + security_group=['default']) try: - self.assertEqual(len(ref[0]['security_groups']), 1) + self.assertEqual(len(db.security_group_get_by_instance( + self.context, ref[0]['id'])), 1) finally: db.security_group_destroy(self.context, group['id']) db.instance_destroy(self.context, ref[0]['id']) diff --git a/nova/tests/easy_unittest.py b/nova/tests/easy_unittest.py index ed223831f..81990d842 100644 --- a/nova/tests/easy_unittest.py +++ b/nova/tests/easy_unittest.py @@ -28,7 +28,8 @@ from nova import exception from nova import test from nova import utils from nova.api import easy - +from nova.compute import api as compute_api +from nova.tests import cloud_unittest class FakeService(object): def echo(self, context, data): @@ -83,3 +84,19 @@ class EasyTestCase(test.TestCase): proxy = easy.Proxy(self.router) rv = proxy.fake.echo(self.context, data='baz') self.assertEqual(rv['data'], 'baz') + + +class EasyCloudTestCase(cloud_unittest.CloudTestCase): + def setUp(self): + super(EasyCloudTestCase, self).setUp() + compute_handle = compute_api.ComputeAPI(self.cloud.network_manager, + self.cloud.image_service) + easy.register_service('compute', compute_handle) + self.router = easy.JsonParamsMiddleware(easy.SundayMorning()) + proxy = easy.Proxy(self.router) + self.cloud.compute_api = proxy.compute + + def tearDown(self): + super(EasyCloudTestCase, self).tearDown() + easy.EASY_ROUTES = {} + diff --git a/nova/utils.py b/nova/utils.py index b9045a50c..7a98ffa5a 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -22,6 +22,7 @@ System-level utilities and helper functions. import datetime import inspect +import json import logging import os import random @@ -361,3 +362,33 @@ def utf8(value): return value.encode("utf-8") assert isinstance(value, str) return value + + +def to_primitive(value): + if type(value) is type([]) or type(value) is type((None,)): + o = [] + for v in value: + o.append(to_primitive(v)) + return o + elif type(value) is type({}): + o = {} + for k, v in value.iteritems(): + o[k] = to_primitive(v) + return o + elif isinstance(value, datetime.datetime): + return str(value) + else: + return value + + +def dumps(value): + try: + return json.dumps(value) + except TypeError: + pass + + return json.dumps(to_primitive(value)) + + +def loads(s): + return json.loads(s) diff --git a/nova/wsgi.py b/nova/wsgi.py index 2ad27dd7e..c40f043f9 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -21,7 +21,6 @@ Utility methods for working with WSGI servers """ -import json import logging import sys from xml.dom import minidom @@ -35,6 +34,7 @@ import webob import webob.dec import webob.exc +from nova import utils logging.getLogger("routes.middleware").addHandler(logging.StreamHandler()) @@ -322,7 +322,7 @@ class Serializer(object): try: is_xml = (datastring[0] == '<') if not is_xml: - return json.loads(datastring) + return utils.loads(datastring) return self._from_xml(datastring) except: return None @@ -355,7 +355,7 @@ class Serializer(object): return result def _to_json(self, data): - return json.dumps(data) + return utils.dumps(data) def _to_xml(self, data): metadata = self.metadata.get('application/xml', {}) From 4b8270c54697c2c306b750e4a340dbc3021c0620 Mon Sep 17 00:00:00 2001 From: NTT PF Lab Date: Fri, 24 Dec 2010 20:38:49 +0900 Subject: [PATCH 05/31] Support IPv6 --- bin/nova-manage | 12 ++++-- nova/test.py | 3 +- nova/tests/api_unittest.py | 67 ++++++++++++++++++++++++++++++++++ nova/tests/network_unittest.py | 21 +++++++++++ nova/utils.py | 39 ++++++++++++++++++++ 5 files changed, 137 insertions(+), 5 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index 0c1b621ed..e0f6f9323 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -87,7 +87,7 @@ flags.DECLARE('num_networks', 'nova.network.manager') flags.DECLARE('network_size', 'nova.network.manager') flags.DECLARE('vlan_start', 'nova.network.manager') flags.DECLARE('vpn_start', 'nova.network.manager') - +flags.DECLARE('fixed_range_v6', 'nova.network.manager') class VpnCommands(object): """Class for managing VPNs.""" @@ -411,11 +411,11 @@ class NetworkCommands(object): """Class for managing networks.""" def create(self, fixed_range=None, num_networks=None, - network_size=None, vlan_start=None, vpn_start=None): + network_size=None, vlan_start=None, vpn_start=None,fixed_range_v6=None): """Creates fixed ips for host by range arguments: [fixed_range=FLAG], [num_networks=FLAG], [network_size=FLAG], [vlan_start=FLAG], - [vpn_start=FLAG]""" + [vpn_start=FLAG],[fixed_range_v6=FLAG]""" if not fixed_range: fixed_range = FLAGS.fixed_range if not num_networks: @@ -426,11 +426,15 @@ class NetworkCommands(object): vlan_start = FLAGS.vlan_start if not vpn_start: vpn_start = FLAGS.vpn_start + if not fixed_range_v6: + fixed_range_v6 = FLAGS.fixed_range_v6 net_manager = utils.import_object(FLAGS.network_manager) net_manager.create_networks(context.get_admin_context(), fixed_range, int(num_networks), int(network_size), int(vlan_start), - int(vpn_start)) + int(vpn_start),fixed_range_v6) + + CATEGORIES = [ ('user', UserCommands), diff --git a/nova/test.py b/nova/test.py index 5c2a72819..ee2fc2720 100644 --- a/nova/test.py +++ b/nova/test.py @@ -70,7 +70,8 @@ class TrialTestCase(unittest.TestCase): FLAGS.fixed_range, 5, 16, FLAGS.vlan_start, - FLAGS.vpn_start) + FLAGS.vpn_start, + FLAGS.fixed_range_v6) # emulate some of the mox stuff, we can't use the metaclass # because it screws with our generators diff --git a/nova/tests/api_unittest.py b/nova/tests/api_unittest.py index 33d4cb294..a508235c4 100644 --- a/nova/tests/api_unittest.py +++ b/nova/tests/api_unittest.py @@ -24,6 +24,7 @@ import httplib import random import StringIO import webob +import logging from nova import context from nova import flags @@ -265,6 +266,72 @@ class ApiEc2TestCase(test.TrialTestCase): return + def test_authorize_revoke_security_group_cidr_v6(self): + """ + Test that we can add and remove CIDR based rules + to a security group for IPv6 + """ + self.expect_http() + self.mox.ReplayAll() + user = self.manager.create_user('fake', 'fake', 'fake') + project = self.manager.create_project('fake', 'fake', 'fake') + + # At the moment, you need both of these to actually be netadmin + self.manager.add_role('fake', 'netadmin') + project.add_role('fake', 'netadmin') + + security_group_name = "".join(random.choice("sdiuisudfsdcnpaqwertasd") + for x in range(random.randint(4, 8))) + + group = self.ec2.create_security_group(security_group_name, + 'test group') + + self.expect_http() + self.mox.ReplayAll() + group.connection = self.ec2 + + group.authorize('tcp', 80, 81, '::/0') + + self.expect_http() + self.mox.ReplayAll() + + rv = self.ec2.get_all_security_groups() + # I don't bother checkng that we actually find it here, + # because the create/delete unit test further up should + # be good enough for that. + for group in rv: + if group.name == security_group_name: + self.assertEquals(len(group.rules), 1) + self.assertEquals(int(group.rules[0].from_port), 80) + self.assertEquals(int(group.rules[0].to_port), 81) + self.assertEquals(len(group.rules[0].grants), 1) + self.assertEquals(str(group.rules[0].grants[0]), '::/0') + + self.expect_http() + self.mox.ReplayAll() + group.connection = self.ec2 + + group.revoke('tcp', 80, 81, '::/0') + + self.expect_http() + self.mox.ReplayAll() + + self.ec2.delete_security_group(security_group_name) + + self.expect_http() + self.mox.ReplayAll() + group.connection = self.ec2 + + rv = self.ec2.get_all_security_groups() + + self.assertEqual(len(rv), 1) + self.assertEqual(rv[0].name, 'default') + + self.manager.delete_project(project) + self.manager.delete_user(user) + + return + def test_authorize_revoke_security_group_foreign_group(self): """ Test that we can grant and revoke another security group access diff --git a/nova/tests/network_unittest.py b/nova/tests/network_unittest.py index 6f4705719..0a4b50e96 100644 --- a/nova/tests/network_unittest.py +++ b/nova/tests/network_unittest.py @@ -97,6 +97,27 @@ class NetworkTestCase(test.TrialTestCase): 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(1) + network_ref = db.project_get_network( + self.context, + self.context.project_id) + address_v6 = db.instance_get_fixed_address_v6( + self.context, + instance_ref['id']) + self.assertEqual(instance_ref['mac_address'], + utils.to_mac(address_v6)) + instance_ref2 = db.fixed_ip_get_instance_v6( + self.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'])) + def test_public_network_association(self): """Makes sure that we can allocaate a public ip""" # TODO(vish): better way of adding floating ips diff --git a/nova/utils.py b/nova/utils.py index 142584df8..211a2cb75 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -30,6 +30,8 @@ import subprocess import socket import sys from xml.sax import saxutils +import re +import netaddr from twisted.internet.threads import deferToThread @@ -45,10 +47,14 @@ TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ" def import_class(import_str): """Returns a class from a string including module and class""" mod_str, _sep, class_str = import_str.rpartition('.') + logging.debug(import_str) try: __import__(mod_str) return getattr(sys.modules[mod_str], class_str) except (ImportError, ValueError, AttributeError): + logging.debug(ImportError) + logging.debug(ValueError) + logging.debug(AttributeError) raise exception.NotFound('Class %s cannot be found' % class_str) @@ -165,6 +171,39 @@ def get_my_ip(): return "127.0.0.1" +def get_my_linklocal(interface): + if getattr(FLAGS, 'fake_tests', None): + return 'fe00::' + try: + if_str = execute("ifconfig %s" % interface) + condition = "\s+inet6\s+addr:\s+([0-9a-f:]+/\d+)\s+Scope:Link" + links = [re.search(condition, x) for x in if_str[0].split('\n')] + address = [w.group(1) for w in links if w is not None] + if address[0] is not None: + return address[0] + else: + return None + except RuntimeError as ex: + logging.warn("Couldn't get Link Local IP of %s :%s", interface, ex) + return None + + +def to_global_ipv6(prefix, mac): + mac64 = netaddr.EUI(mac).eui64().words + int_addr = int(''.join(['%02x' % i for i in mac64]), 16) + mac64_addr = netaddr.IPAddress(int_addr) + maskIP = netaddr.IPNetwork(prefix).ip + return (mac64_addr ^ netaddr.IPAddress('::0200:0:0:0') | maskIP).format() + + +def to_mac(ipv6_address): + address = netaddr.IPAddress(ipv6_address) + mask1 = netaddr.IPAddress("::ffff:ffff:ffff:ffff") + mask2 = netaddr.IPAddress("::0200:0:0:0") + mac64 = netaddr.EUI(int(address & mask1 ^ mask2)).words + return ":".join(["%02x" % i for i in mac64[0:3] + mac64[5:8]]) + + def isotime(at=None): if not at: at = datetime.datetime.utcnow() From 385cdfdea7f33dbce48e7a1ea60d2d8f82a6f046 Mon Sep 17 00:00:00 2001 From: Andy Smith Date: Mon, 27 Dec 2010 15:15:24 -0800 Subject: [PATCH 06/31] Added stack command-line tool --- bin/nova-easy-api | 61 +++++++++++++++ bin/stack | 145 ++++++++++++++++++++++++++++++++++++ nova/tests/easy_unittest.py | 6 +- nova/utils.py | 2 +- nova/wsgi.py | 3 +- 5 files changed, 211 insertions(+), 6 deletions(-) create mode 100755 bin/nova-easy-api create mode 100755 bin/stack diff --git a/bin/nova-easy-api b/bin/nova-easy-api new file mode 100755 index 000000000..e8e86b4fb --- /dev/null +++ b/bin/nova-easy-api @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# pylint: disable-msg=C0103 +# 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. + +"""Starter script for Nova Easy API.""" + +import gettext +import os +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 nova import flags +from nova import utils +from nova import wsgi +from nova.api import easy +from nova.compute import api as compute_api + + +FLAGS = flags.FLAGS +flags.DEFINE_integer('easy_port', 8001, 'Easy API port') +flags.DEFINE_string('easy_host', '0.0.0.0', 'Easy API host') + +if __name__ == '__main__': + utils.default_flagfile() + FLAGS(sys.argv) + + easy.register_service('compute', compute_api.ComputeAPI()) + easy.register_service('reflect', easy.Reflection()) + router = easy.SundayMorning() + with_json = easy.JsonParamsMiddleware(router) + with_req = easy.ReqParamsMiddleware(with_json) + with_auth = easy.DelegatedAuthMiddleware(with_req) + + server = wsgi.Server() + server.start(with_auth, FLAGS.easy_port, host=FLAGS.easy_host) + server.wait() diff --git a/bin/stack b/bin/stack new file mode 100755 index 000000000..284dbf4fc --- /dev/null +++ b/bin/stack @@ -0,0 +1,145 @@ +#!/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. + +"""CLI for the Easy API.""" + +import eventlet +eventlet.monkey_patch() + +import os +import pprint +import sys +import textwrap +import urllib +import urllib2 + +# 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) + +import gflags +from nova import utils + + +FLAGS = gflags.FLAGS +gflags.DEFINE_string('host', '127.0.0.1', 'Easy API host') +gflags.DEFINE_integer('port', 8001, 'Easy API host') +gflags.DEFINE_string('user', 'user1', 'Easy API username') +gflags.DEFINE_string('project', 'proj1', 'Easy API project') + + +USAGE = """usage: stack [options] [arg1=value arg2=value] + + `stack help` should output the list of available controllers + `stack ` should output the available methods for that controller + `stack help ` should do the same + `stack help ` should output info for a method +""" + + +def format_help(d): + """Format help text, keys are labels and values are descriptions.""" + indent = max([len(k) for k in d]) + out = [] + for k, v in d.iteritems(): + t = textwrap.TextWrapper(initial_indent=' %s ' % k.ljust(indent), + subsequent_indent=' ' * (indent + 6)) + out.extend(t.wrap(v)) + return out + + +def help_all(): + rv = do_request('reflect', 'get_controllers') + out = format_help(rv) + return (USAGE + str(FLAGS.MainModuleHelp()) + + '\n\nAvailable controllers:\n' + + '\n'.join(out) + '\n') + + +def help_controller(controller): + rv = do_request('reflect', 'get_methods') + methods = dict([(k.split('/')[2], v) for k, v in rv.iteritems() + if k.startswith('/%s' % controller)]) + return ('Available methods for %s:\n' % controller + + '\n'.join(format_help(methods))) + + +def help_method(controller, method): + rv = do_request('reflect', + 'get_method_info', + {'method': '/%s/%s' % (controller, method)}) + + sig = '%s(%s):' % (method, ', '.join(['='.join(x) for x in rv['args']])) + out = textwrap.wrap(sig, subsequent_indent=' ' * len('%s(' % method)) + out.append('\n' + rv['doc']) + return '\n'.join(out) + + +def do_request(controller, method, params=None): + if params: + data = urllib.urlencode(params) + else: + data = None + + url = 'http://%s:%s/%s/%s' % (FLAGS.host, FLAGS.port, controller, method) + headers = {'X-OpenStack-User': FLAGS.user, + 'X-OpenStack-Project': FLAGS.project} + + req = urllib2.Request(url, data, headers) + resp = urllib2.urlopen(req) + return utils.loads(resp.read()) + + +if __name__ == '__main__': + args = FLAGS(sys.argv) + + cmd = args.pop(0) + if not args: + print help_all() + sys.exit() + + first = args.pop(0) + if first == 'help': + action = help_all + params = [] + if args: + params.append(args.pop(0)) + action = help_controller + if args: + params.append(args.pop(0)) + action = help_method + print action(*params) + sys.exit(0) + + controller = first + if not args: + print help_controller(controller) + sys.exit() + + method = args.pop(0) + params = {} + for x in args: + key, value = args.split('=', 1) + params[key] = value + + pprint.pprint(do_request(controller, method, params)) diff --git a/nova/tests/easy_unittest.py b/nova/tests/easy_unittest.py index 81990d842..cd13c7710 100644 --- a/nova/tests/easy_unittest.py +++ b/nova/tests/easy_unittest.py @@ -31,6 +31,7 @@ from nova.api import easy from nova.compute import api as compute_api from nova.tests import cloud_unittest + class FakeService(object): def echo(self, context, data): return {'data': data} @@ -49,7 +50,7 @@ class EasyTestCase(test.TestCase): easy.SundayMorning())) self.auth_router = easy.DelegatedAuthMiddleware(self.router) self.context = context.RequestContext('user1', 'proj1') - + def tearDown(self): easy.EASY_ROUTES = {} @@ -61,7 +62,7 @@ class EasyTestCase(test.TestCase): data = json.loads(resp.body) self.assertEqual(data['user'], 'user1') self.assertEqual(data['project'], 'proj1') - + def test_json_params(self): req = webob.Request.blank('/fake/echo') req.environ['openstack.context'] = self.context @@ -99,4 +100,3 @@ class EasyCloudTestCase(cloud_unittest.CloudTestCase): def tearDown(self): super(EasyCloudTestCase, self).tearDown() easy.EASY_ROUTES = {} - diff --git a/nova/utils.py b/nova/utils.py index 7a98ffa5a..337924f10 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -386,7 +386,7 @@ def dumps(value): return json.dumps(value) except TypeError: pass - + return json.dumps(to_primitive(value)) diff --git a/nova/wsgi.py b/nova/wsgi.py index c40f043f9..564805ae7 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -105,8 +105,7 @@ class Application(object): class Middleware(Application): """Base WSGI middleware. - - Modelled after Django's middleware this class allows you to + These classes require an application to be initialized that will be called next. By default the middleware will simply call its wrapped app, or you can override __call__ to customize its From fcc430b30db27b2ed6ff58fcbb2c27bc98126341 Mon Sep 17 00:00:00 2001 From: Nachi Ueno Date: Tue, 4 Jan 2011 07:40:29 -0500 Subject: [PATCH 07/31] Some Bug Fix --- nova/utils.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nova/utils.py b/nova/utils.py index 0eab4b152..c5e2f7517 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -211,8 +211,6 @@ def get_my_ip(): def get_my_linklocal(interface): - if getattr(FLAGS, 'fake_tests', None): - return 'fe00::' try: if_str = execute("ifconfig %s" % interface) condition = "\s+inet6\s+addr:\s+([0-9a-f:]+/\d+)\s+Scope:Link" @@ -224,7 +222,7 @@ def get_my_linklocal(interface): return None except RuntimeError as ex: logging.warn("Couldn't get Link Local IP of %s :%s", interface, ex) - return None + return 'fe00::' def to_global_ipv6(prefix, mac): From ae6e77a0893b45531c861909f6044bc0205cbf82 Mon Sep 17 00:00:00 2001 From: Andy Smith Date: Tue, 4 Jan 2011 14:07:46 -0800 Subject: [PATCH 08/31] rename Easy API to Direct API --- bin/{nova-easy-api => nova-direct-api} | 20 +++++------ .../{easy_unittest.py => test_direct.py} | 36 +++++++++---------- 2 files changed, 28 insertions(+), 28 deletions(-) rename bin/{nova-easy-api => nova-direct-api} (75%) rename nova/tests/{easy_unittest.py => test_direct.py} (77%) diff --git a/bin/nova-easy-api b/bin/nova-direct-api similarity index 75% rename from bin/nova-easy-api rename to bin/nova-direct-api index e8e86b4fb..43046e6c2 100755 --- a/bin/nova-easy-api +++ b/bin/nova-direct-api @@ -37,25 +37,25 @@ gettext.install('nova', unicode=1) from nova import flags from nova import utils from nova import wsgi -from nova.api import easy +from nova.api import direct from nova.compute import api as compute_api FLAGS = flags.FLAGS -flags.DEFINE_integer('easy_port', 8001, 'Easy API port') -flags.DEFINE_string('easy_host', '0.0.0.0', 'Easy API host') +flags.DEFINE_integer('direct_port', 8001, 'Direct API port') +flags.DEFINE_string('direct_host', '0.0.0.0', 'Direct API host') if __name__ == '__main__': utils.default_flagfile() FLAGS(sys.argv) - easy.register_service('compute', compute_api.ComputeAPI()) - easy.register_service('reflect', easy.Reflection()) - router = easy.SundayMorning() - with_json = easy.JsonParamsMiddleware(router) - with_req = easy.ReqParamsMiddleware(with_json) - with_auth = easy.DelegatedAuthMiddleware(with_req) + direct.register_service('compute', compute_api.ComputeAPI()) + direct.register_service('reflect', direct.Reflection()) + router = direct.Router() + with_json = direct.JsonParamsMiddleware(router) + with_req = direct.PostParamsMiddleware(with_json) + with_auth = direct.DelegatedAuthMiddleware(with_req) server = wsgi.Server() - server.start(with_auth, FLAGS.easy_port, host=FLAGS.easy_host) + server.start(with_auth, FLAGS.direct_port, host=FLAGS.direct_host) server.wait() diff --git a/nova/tests/easy_unittest.py b/nova/tests/test_direct.py similarity index 77% rename from nova/tests/easy_unittest.py rename to nova/tests/test_direct.py index cd13c7710..d73c64ce0 100644 --- a/nova/tests/easy_unittest.py +++ b/nova/tests/test_direct.py @@ -16,7 +16,7 @@ # License for the specific language governing permissions and limitations # under the License. -"""Tests for Easy API.""" +"""Tests for Direct API.""" import json import logging @@ -27,7 +27,7 @@ from nova import context from nova import exception from nova import test from nova import utils -from nova.api import easy +from nova.api import direct from nova.compute import api as compute_api from nova.tests import cloud_unittest @@ -41,18 +41,18 @@ class FakeService(object): 'project': context.project_id} -class EasyTestCase(test.TestCase): +class DirectTestCase(test.TestCase): def setUp(self): - super(EasyTestCase, self).setUp() - easy.register_service('fake', FakeService()) - self.router = easy.ReqParamsMiddleware( - easy.JsonParamsMiddleware( - easy.SundayMorning())) - self.auth_router = easy.DelegatedAuthMiddleware(self.router) + super(DirectTestCase, self).setUp() + direct.register_service('fake', FakeService()) + self.router = direct.PostParamsMiddleware( + direct.JsonParamsMiddleware( + direct.Router())) + self.auth_router = direct.DelegatedAuthMiddleware(self.router) self.context = context.RequestContext('user1', 'proj1') def tearDown(self): - easy.EASY_ROUTES = {} + direct.ROUTES = {} def test_delegated_auth(self): req = webob.Request.blank('/fake/context') @@ -82,21 +82,21 @@ class EasyTestCase(test.TestCase): self.assertEqual(resp_parsed['data'], 'foo') def test_proxy(self): - proxy = easy.Proxy(self.router) + proxy = direct.Proxy(self.router) rv = proxy.fake.echo(self.context, data='baz') self.assertEqual(rv['data'], 'baz') -class EasyCloudTestCase(cloud_unittest.CloudTestCase): +class DirectCloudTestCase(cloud_unittest.CloudTestCase): def setUp(self): - super(EasyCloudTestCase, self).setUp() + super(DirectCloudTestCase, self).setUp() compute_handle = compute_api.ComputeAPI(self.cloud.network_manager, self.cloud.image_service) - easy.register_service('compute', compute_handle) - self.router = easy.JsonParamsMiddleware(easy.SundayMorning()) - proxy = easy.Proxy(self.router) + direct.register_service('compute', compute_handle) + self.router = direct.JsonParamsMiddleware(direct.Router()) + proxy = direct.Proxy(self.router) self.cloud.compute_api = proxy.compute def tearDown(self): - super(EasyCloudTestCase, self).tearDown() - easy.EASY_ROUTES = {} + super(DirectCloudTestCase, self).tearDown() + direct.ROUTES = {} From 2972fa4af86a0e9b61a734c44a67e02cc5bbc72e Mon Sep 17 00:00:00 2001 From: Andy Smith Date: Tue, 4 Jan 2011 14:37:04 -0800 Subject: [PATCH 09/31] fix typo in stack tool --- bin/stack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/stack b/bin/stack index 284dbf4fc..42feacd63 100755 --- a/bin/stack +++ b/bin/stack @@ -139,7 +139,7 @@ if __name__ == '__main__': method = args.pop(0) params = {} for x in args: - key, value = args.split('=', 1) + key, value = x.split('=', 1) params[key] = value pprint.pprint(do_request(controller, method, params)) From 7bf0430259bfa61d0076ceba1636ea5c7f260ffe Mon Sep 17 00:00:00 2001 From: Andy Smith Date: Tue, 4 Jan 2011 14:39:48 -0800 Subject: [PATCH 10/31] rename easy to direct in the scripts --- bin/nova-direct-api | 2 +- bin/stack | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/nova-direct-api b/bin/nova-direct-api index 43046e6c2..e7dd14fb2 100755 --- a/bin/nova-direct-api +++ b/bin/nova-direct-api @@ -18,7 +18,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Starter script for Nova Easy API.""" +"""Starter script for Nova Direct API.""" import gettext import os diff --git a/bin/stack b/bin/stack index 42feacd63..7a6ce5960 100755 --- a/bin/stack +++ b/bin/stack @@ -17,7 +17,7 @@ # License for the specific language governing permissions and limitations # under the License. -"""CLI for the Easy API.""" +"""CLI for the Direct API.""" import eventlet eventlet.monkey_patch() @@ -42,10 +42,10 @@ from nova import utils FLAGS = gflags.FLAGS -gflags.DEFINE_string('host', '127.0.0.1', 'Easy API host') -gflags.DEFINE_integer('port', 8001, 'Easy API host') -gflags.DEFINE_string('user', 'user1', 'Easy API username') -gflags.DEFINE_string('project', 'proj1', 'Easy API project') +gflags.DEFINE_string('host', '127.0.0.1', 'Direct API host') +gflags.DEFINE_integer('port', 8001, 'Direct API host') +gflags.DEFINE_string('user', 'user1', 'Direct API username') +gflags.DEFINE_string('project', 'proj1', 'Direct API project') USAGE = """usage: stack [options] [arg1=value arg2=value] From 869cce247bbd431fa54356ab042bc91729eb5c8e Mon Sep 17 00:00:00 2001 From: Nachi Ueno Date: Wed, 5 Jan 2011 12:39:35 -0500 Subject: [PATCH 11/31] missing _() --- nova/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/utils.py b/nova/utils.py index c5e2f7517..afe7422d9 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -221,7 +221,7 @@ def get_my_linklocal(interface): else: return None except RuntimeError as ex: - logging.warn("Couldn't get Link Local IP of %s :%s", interface, ex) + logging.warn(_("Couldn't get Link Local IP of %s :%s"), interface, ex) return 'fe00::' From 1555065712931b5a7ec27aa4380d2bdd5ddaa6cf Mon Sep 17 00:00:00 2001 From: Ed Leafe Date: Thu, 6 Jan 2011 06:45:14 -0600 Subject: [PATCH 12/31] Renamed 'set_root_password' to 'set_admin_password' globally. --- nova/tests/test_compute.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 7c258e636..88e14d7df 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -151,11 +151,11 @@ class ComputeTestCase(test.TestCase): self.compute.reboot_instance(self.context, instance_id) self.compute.terminate_instance(self.context, instance_id) - def test_reset_root_password(self): - """Ensure instance can have its root password reset""" + def test_set_admin_password(self): + """Ensure instance can have its admin password set""" instance_id = self._create_instance() self.compute.run_instance(self.context, instance_id) - self.compute.reset_root_password(self.context, instance_id) + self.compute.set_admin_password(self.context, instance_id) self.compute.terminate_instance(self.context, instance_id) def test_snapshot(self): From e9c403b21c5763f967654bb7e8d4c9f7ceb26a2e Mon Sep 17 00:00:00 2001 From: Ed Leafe Date: Thu, 6 Jan 2011 15:53:11 -0600 Subject: [PATCH 13/31] Got the basic 'set admin password' stuff working --- nova/exception.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nova/exception.py b/nova/exception.py index 277033e0f..52bf2a2a7 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -77,6 +77,10 @@ class InvalidInputException(Error): pass +class TimeoutException(Error): + pass + + def wrap_exception(f): def _wrap(*args, **kw): try: From e36581ea17a13c96ab56777d073c59539f5b581b Mon Sep 17 00:00:00 2001 From: Andy Smith Date: Fri, 7 Jan 2011 13:02:55 -0800 Subject: [PATCH 14/31] set the hostname factory in the service init --- nova/tests/test_direct.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/tests/test_direct.py b/nova/tests/test_direct.py index d73c64ce0..78ad8ffed 100644 --- a/nova/tests/test_direct.py +++ b/nova/tests/test_direct.py @@ -72,7 +72,7 @@ class DirectTestCase(test.TestCase): resp_parsed = json.loads(resp.body) self.assertEqual(resp_parsed['data'], 'foo') - def test_req_params(self): + def test_post_params(self): req = webob.Request.blank('/fake/echo') req.environ['openstack.context'] = self.context req.method = 'POST' From e5e763e7d551a0917d5fd573180f8b2fdb8227be Mon Sep 17 00:00:00 2001 From: Andy Smith Date: Fri, 7 Jan 2011 16:05:06 -0800 Subject: [PATCH 15/31] some small cleanups --- nova/tests/test_direct.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/nova/tests/test_direct.py b/nova/tests/test_direct.py index 5c6ecd903..8a74b2296 100644 --- a/nova/tests/test_direct.py +++ b/nova/tests/test_direct.py @@ -101,7 +101,3 @@ class DirectCloudTestCase(test_cloud.CloudTestCase): def tearDown(self): super(DirectCloudTestCase, self).tearDown() direct.ROUTES = {} - -if __name__ == '__main__': - import unittest - unittest.main() From 692eda29bbbbba71fa8726cc2886d75d7c98a12e Mon Sep 17 00:00:00 2001 From: Nachi Ueno Date: Wed, 12 Jan 2011 02:15:09 -0500 Subject: [PATCH 16/31] changed exception class --- nova/utils.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/nova/utils.py b/nova/utils.py index afe7422d9..888ebfd81 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -219,10 +219,13 @@ def get_my_linklocal(interface): if address[0] is not None: return address[0] else: - return None - except RuntimeError as ex: - logging.warn(_("Couldn't get Link Local IP of %s :%s"), interface, ex) - return 'fe00::' + return 'fe00::' + except IndexError as ex: + logging.warn(_("Couldn't parse command from get Link Local IP of %s :%s"), interface, ex) + except ProcessExecutionError as ex: + logging.warn(_("Couldn't execute command to get Link Local IP of %s :%s"), interface, ex) + except: + return 'fe00::' def to_global_ipv6(prefix, mac): From 5c20a62f8a6a5e071c6a5714f4d667ad4d53ea5e Mon Sep 17 00:00:00 2001 From: Hisaharu Ishii Date: Wed, 12 Jan 2011 11:26:22 +0900 Subject: [PATCH 17/31] Fixed for pep8 Remove temporary debugging --- bin/nova-manage | 10 +++++----- nova/utils.py | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index 04ecc8c10..7331186c7 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -91,6 +91,7 @@ flags.DECLARE('vlan_start', 'nova.network.manager') flags.DECLARE('vpn_start', 'nova.network.manager') flags.DECLARE('fixed_range_v6', 'nova.network.manager') + class VpnCommands(object): """Class for managing VPNs.""" @@ -432,11 +433,12 @@ class NetworkCommands(object): """Class for managing networks.""" def create(self, fixed_range=None, num_networks=None, - network_size=None, vlan_start=None, vpn_start=None,fixed_range_v6=None): + network_size=None, vlan_start=None, vpn_start=None, + fixed_range_v6=None): """Creates fixed ips for host by range arguments: [fixed_range=FLAG], [num_networks=FLAG], [network_size=FLAG], [vlan_start=FLAG], - [vpn_start=FLAG],[fixed_range_v6=FLAG]""" + [vpn_start=FLAG], [fixed_range_v6=FLAG]""" if not fixed_range: fixed_range = FLAGS.fixed_range if not num_networks: @@ -453,9 +455,7 @@ class NetworkCommands(object): net_manager.create_networks(context.get_admin_context(), fixed_range, int(num_networks), int(network_size), int(vlan_start), - int(vpn_start),fixed_range_v6) - - + int(vpn_start), fixed_range_v6) class ServiceCommands(object): diff --git a/nova/utils.py b/nova/utils.py index 888ebfd81..b08d5d620 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -47,7 +47,6 @@ TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ" def import_class(import_str): """Returns a class from a string including module and class""" mod_str, _sep, class_str = import_str.rpartition('.') - logging.debug(import_str) try: __import__(mod_str) return getattr(sys.modules[mod_str], class_str) From bac2ce71399bb57ec30775604cc48f9febd354b2 Mon Sep 17 00:00:00 2001 From: Hisaharu Ishii Date: Wed, 12 Jan 2011 18:37:18 +0900 Subject: [PATCH 18/31] Change command to get link local address Remove superfluous code --- nova/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/utils.py b/nova/utils.py index 02bafc6c8..a13fa214c 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -212,8 +212,8 @@ def get_my_ip(): def get_my_linklocal(interface): try: - if_str = execute("ifconfig %s" % interface) - condition = "\s+inet6\s+addr:\s+([0-9a-f:]+/\d+)\s+Scope:Link" + if_str = execute("ip -f inet6 -o addr show %s" % interface) + condition = "\s+inet6\s+([0-9a-f:]+/\d+)\s+scope:link" links = [re.search(condition, x) for x in if_str[0].split('\n')] address = [w.group(1) for w in links if w is not None] if address[0] is not None: From b0c155813a7b6b634b9590754cf0a45f637d3de2 Mon Sep 17 00:00:00 2001 From: Nachi Ueno Date: Wed, 12 Jan 2011 10:12:18 -0500 Subject: [PATCH 19/31] Fixed syntax errors --- nova/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/utils.py b/nova/utils.py index 49344699a..09c9a5f89 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -218,7 +218,7 @@ def get_my_ip(): def get_my_linklocal(interface): try: if_str = execute("ip -f inet6 -o addr show %s" % interface) - condition = "\s+inet6\s+([0-9a-f:]+/\d+)\s+scope:link" + condition = "\s+inet6\s+([0-9a-f:]+/\d+)\s+scope\s+link" links = [re.search(condition, x) for x in if_str[0].split('\n')] address = [w.group(1) for w in links if w is not None] if address[0] is not None: From 4899e8bc49a8dc93c2de57a3cd5b8fe04bf54d57 Mon Sep 17 00:00:00 2001 From: Nachi Ueno Date: Thu, 13 Jan 2011 09:10:44 +0900 Subject: [PATCH 20/31] fixed method signature of modify_rules fixed unit_test for ipv6 --- nova/tests/test_network.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/nova/tests/test_network.py b/nova/tests/test_network.py index 407dbc769..00f9323f3 100644 --- a/nova/tests/test_network.py +++ b/nova/tests/test_network.py @@ -99,23 +99,24 @@ class NetworkTestCase(test.TestCase): def test_private_ipv6(self): """Make sure ipv6 is OK""" if FLAGS.use_ipv6: - instance_ref = self._create_instance(1) + instance_ref = self._create_instance(0) + address = self._create_address(0, instance_ref['id']) network_ref = db.project_get_network( - self.context, + context.get_admin_context(), self.context.project_id) address_v6 = db.instance_get_fixed_address_v6( - self.context, - instance_ref['id']) + 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( - self.context, - address_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'])) + network_ref['cidr_v6'], + instance_ref['mac_address'])) def test_public_network_association(self): """Makes sure that we can allocaate a public ip""" From fe183e2a3ebaca7f6f9534c29b90c70e03b87c93 Mon Sep 17 00:00:00 2001 From: Koji Iida Date: Thu, 13 Jan 2011 15:58:05 +0900 Subject: [PATCH 21/31] Fixed missing _(). Fixed to follow logging to LOG changes. Fixed merge miss (get_fixed_ip was moved away). Update some missing comments. --- nova/tests/test_api.py | 1 - nova/utils.py | 17 ++--------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py index a508235c4..d22d7beb1 100644 --- a/nova/tests/test_api.py +++ b/nova/tests/test_api.py @@ -24,7 +24,6 @@ import httplib import random import StringIO import webob -import logging from nova import context from nova import flags diff --git a/nova/utils.py b/nova/utils.py index 09c9a5f89..27589c30c 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -202,19 +202,6 @@ def last_octet(address): return int(address.split(".")[-1]) -def get_my_ip(): - """Returns the actual ip of the local machine.""" - try: - csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - csock.connect(('8.8.8.8', 80)) - (addr, port) = csock.getsockname() - csock.close() - return addr - except socket.gaierror as ex: - logging.warn(_("Couldn't get IP, using 127.0.0.1 %s"), ex) - return "127.0.0.1" - - def get_my_linklocal(interface): try: if_str = execute("ip -f inet6 -o addr show %s" % interface) @@ -226,9 +213,9 @@ def get_my_linklocal(interface): else: return 'fe00::' except IndexError as ex: - logging.warn(_("Couldn't get Link Local IP of %s :%s"), interface, ex) + LOG.warn(_("Couldn't get Link Local IP of %s :%s"), interface, ex) except ProcessExecutionError as ex: - logging.warn(_("Couldn't get Link Local IP of %s :%s"), interface, ex) + LOG.warn(_("Couldn't get Link Local IP of %s :%s"), interface, ex) except: return 'fe00::' From c9d0c8bebc6ef3301510d3417ccc4fcc7984f45b Mon Sep 17 00:00:00 2001 From: Hisaharu Ishii Date: Thu, 13 Jan 2011 16:59:29 +0900 Subject: [PATCH 22/31] Fixed Authors --- Authors | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Authors b/Authors index 7bcd5981f..479b796ba 100644 --- a/Authors +++ b/Authors @@ -45,7 +45,7 @@ Trey Morris Vishvananda Ishaya Youcef Laribi Zhixue Wu -Hisaharu Ishii -Koji Iida +Hisaharu Ishii +Koji Iida Nachi Ueno From c6130bb6d391bc13e56d4062f20ced93559656bb Mon Sep 17 00:00:00 2001 From: Ed Leafe Date: Thu, 13 Jan 2011 10:51:31 -0600 Subject: [PATCH 23/31] Minor code cleanups --- nova/tests/test_xenapi.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index a03d616ad..93afe9ce1 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -265,10 +265,6 @@ class XenAPIVMTestCase(test.TestCase): return instance - - - - class XenAPIDiffieHellmanTestCase(test.TestCase): """ Unit tests for Diffie-Hellman code From 1ae0ee166d66a384a0a89ebeb2928c692211d7df Mon Sep 17 00:00:00 2001 From: Ed Leafe Date: Thu, 13 Jan 2011 10:52:28 -0600 Subject: [PATCH 24/31] Minor code cleanups --- nova/tests/test_xenapi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 93afe9ce1..261ee0fde 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -286,6 +286,6 @@ class XenAPIDiffieHellmanTestCase(test.TestCase): enc = self.alice.encrypt(msg) dec = self.bob.decrypt(enc) self.assertEquals(dec, msg) - + def tearDown(self): super(XenAPIDiffieHellmanTestCase, self).tearDown() From 14ec6db569da0c3808b6d89e2a93dc50a48221d2 Mon Sep 17 00:00:00 2001 From: Hisaharu Ishii Date: Fri, 14 Jan 2011 11:44:35 +0900 Subject: [PATCH 25/31] sort Authors --- Authors | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Authors b/Authors index 479b796ba..74736562e 100644 --- a/Authors +++ b/Authors @@ -1,11 +1,12 @@ + Andy Smith Anne Gentle Anthony Young Antony Messerli Armando Migliaccio Chiradeep Vittal -Chris Behrens Chmouel Boudjnah +Chris Behrens Cory Wright David Pravec Dean Troyer @@ -14,6 +15,7 @@ Ed Leafe Eldar Nugaev Eric Day Ewan Mellor +Hisaharu Ishii Hisaki Ohara Ilya Alekseyev Jay Pipes @@ -26,11 +28,13 @@ Josh Kearney Joshua McKenty Justin Santa Barbara Ken Pepple +Koji Iida Lorin Hochstein Matt Dietz Michael Gundlach Monsyne Dragon Monty Taylor +Nachi Ueno Paul Voccio Rick Clark Rick Harris @@ -45,7 +49,3 @@ Trey Morris Vishvananda Ishaya Youcef Laribi Zhixue Wu -Hisaharu Ishii -Koji Iida -Nachi Ueno - From ac0c679590e26f6249751c1975978109a0b726f7 Mon Sep 17 00:00:00 2001 From: MORITA Kazutaka Date: Fri, 14 Jan 2011 12:25:34 +0900 Subject: [PATCH 26/31] Update Authors --- Authors | 1 + 1 file changed, 1 insertion(+) diff --git a/Authors b/Authors index 0c49f76a2..3c25a8bb1 100644 --- a/Authors +++ b/Authors @@ -25,6 +25,7 @@ Josh Durgin Josh Kearney Joshua McKenty Justin Santa Barbara +MORITA Kazutaka Ken Pepple Lorin Hochstein Matt Dietz From 68bf7e6ef8f65a5a8055ec143fdfdf1a2c81e380 Mon Sep 17 00:00:00 2001 From: MORITA Kazutaka Date: Fri, 14 Jan 2011 12:46:10 +0900 Subject: [PATCH 27/31] Sort Authors --- Authors | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Authors b/Authors index 3c25a8bb1..1b8cee2a1 100644 --- a/Authors +++ b/Authors @@ -25,13 +25,13 @@ Josh Durgin Josh Kearney Joshua McKenty Justin Santa Barbara -MORITA Kazutaka Ken Pepple Lorin Hochstein Matt Dietz Michael Gundlach Monsyne Dragon Monty Taylor +MORITA Kazutaka Paul Voccio Rick Clark Rick Harris From d6329ac7b651a552a3aa73c7d903dc4b9e5b26b6 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 14 Jan 2011 11:00:47 -0800 Subject: [PATCH 29/31] remove TrialTestCase again and fix merge issues --- nova/test.py | 99 +---------------------------------- nova/tests/test_api.py | 4 +- nova/tests/test_log.py | 8 +-- nova/tests/test_middleware.py | 2 +- nova/tests/test_twistd.py | 2 +- 5 files changed, 10 insertions(+), 105 deletions(-) diff --git a/nova/test.py b/nova/test.py index 5922e4b1c..a26b85b04 100644 --- a/nova/test.py +++ b/nova/test.py @@ -23,8 +23,6 @@ and some black magic for inline callbacks. """ import datetime -import sys -import time import unittest import mox @@ -38,7 +36,6 @@ from nova import fakerabbit from nova import flags from nova import rpc from nova.network import manager as network_manager -from nova.tests import fake_flags FLAGS = flags.FLAGS @@ -74,7 +71,8 @@ class TestCase(unittest.TestCase): FLAGS.fixed_range, 5, 16, FLAGS.vlan_start, - FLAGS.vpn_start) + FLAGS.vpn_start, + FLAGS.fixed_range_v6) # emulate some of the mox stuff, we can't use the metaclass # because it screws with our generators @@ -139,96 +137,3 @@ class TestCase(unittest.TestCase): _wrapped.func_name = self.originalAttach.func_name rpc.Consumer.attach_to_eventlet = _wrapped - - -class TrialTestCase(trial_unittest.TestCase): - """Test case base class for all unit tests""" - def setUp(self): - """Run before each test method to initialize test environment""" - super(TrialTestCase, self).setUp() - # NOTE(vish): We need a better method for creating fixtures for tests - # now that we have some required db setup for the system - # to work properly. - self.start = datetime.datetime.utcnow() - ctxt = context.get_admin_context() - if db.network_count(ctxt) != 5: - network_manager.VlanManager().create_networks(ctxt, - FLAGS.fixed_range, - 5, 16, - FLAGS.vlan_start, - FLAGS.vpn_start, - FLAGS.fixed_range_v6) - - # emulate some of the mox stuff, we can't use the metaclass - # because it screws with our generators - self.mox = mox.Mox() - self.stubs = stubout.StubOutForTesting() - self.flag_overrides = {} - self.injected = [] - self._original_flags = FLAGS.FlagValuesDict() - - def tearDown(self): - """Runs after each test method to finalize/tear down test - environment.""" - try: - self.mox.UnsetStubs() - self.stubs.UnsetAll() - self.stubs.SmartUnsetAll() - self.mox.VerifyAll() - # NOTE(vish): Clean up any ips associated during the test. - ctxt = context.get_admin_context() - db.fixed_ip_disassociate_all_by_timeout(ctxt, FLAGS.host, - self.start) - db.network_disassociate_all(ctxt) - for x in self.injected: - try: - x.stop() - except AssertionError: - pass - - if FLAGS.fake_rabbit: - fakerabbit.reset_all() - - db.security_group_destroy_all(ctxt) - super(TrialTestCase, self).tearDown() - finally: - self.reset_flags() - - def flags(self, **kw): - """Override flag variables for a test""" - for k, v in kw.iteritems(): - if k in self.flag_overrides: - self.reset_flags() - raise Exception( - 'trying to override already overriden flag: %s' % k) - self.flag_overrides[k] = getattr(FLAGS, k) - setattr(FLAGS, k, v) - - def reset_flags(self): - """Resets all flag variables for the test. Runs after each test""" - FLAGS.Reset() - for k, v in self._original_flags.iteritems(): - setattr(FLAGS, k, v) - - def run(self, result=None): - test_method = getattr(self, self._testMethodName) - setattr(self, - self._testMethodName, - self._maybeInlineCallbacks(test_method, result)) - rv = super(TrialTestCase, self).run(result) - setattr(self, self._testMethodName, test_method) - return rv - - def _maybeInlineCallbacks(self, func, result): - def _wrapped(): - g = func() - if isinstance(g, defer.Deferred): - return g - if not hasattr(g, 'send'): - return defer.succeed(g) - - inlined = defer.inlineCallbacks(func) - d = inlined() - return d - _wrapped.func_name = func.func_name - return _wrapped diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py index d22d7beb1..17789c25c 100644 --- a/nova/tests/test_api.py +++ b/nova/tests/test_api.py @@ -79,7 +79,7 @@ class FakeHttplibConnection(object): pass -class XmlConversionTestCase(test.TrialTestCase): +class XmlConversionTestCase(test.TestCase): """Unit test api xml conversion""" def test_number_conversion(self): conv = apirequest._try_convert @@ -96,7 +96,7 @@ class XmlConversionTestCase(test.TrialTestCase): self.assertEqual(conv('-0'), 0) -class ApiEc2TestCase(test.TrialTestCase): +class ApiEc2TestCase(test.TestCase): """Unit test for the cloud controller on an EC2 API""" def setUp(self): super(ApiEc2TestCase, self).setUp() diff --git a/nova/tests/test_log.py b/nova/tests/test_log.py index beb1d97cf..868a5ead3 100644 --- a/nova/tests/test_log.py +++ b/nova/tests/test_log.py @@ -9,7 +9,7 @@ def _fake_context(): return context.RequestContext(1, 1) -class RootLoggerTestCase(test.TrialTestCase): +class RootLoggerTestCase(test.TestCase): def setUp(self): super(RootLoggerTestCase, self).setUp() self.log = log.logging.root @@ -46,7 +46,7 @@ class RootLoggerTestCase(test.TrialTestCase): self.assert_(True) # didn't raise exception -class NovaFormatterTestCase(test.TrialTestCase): +class NovaFormatterTestCase(test.TestCase): def setUp(self): super(NovaFormatterTestCase, self).setUp() self.flags(logging_context_format_string="HAS CONTEXT "\ @@ -78,7 +78,7 @@ class NovaFormatterTestCase(test.TrialTestCase): self.assertEqual("NOCTXT: baz --DBG\n", self.stream.getvalue()) -class NovaLoggerTestCase(test.TrialTestCase): +class NovaLoggerTestCase(test.TestCase): def setUp(self): super(NovaLoggerTestCase, self).setUp() self.flags(default_log_levels=["nova-test=AUDIT"], verbose=False) @@ -96,7 +96,7 @@ class NovaLoggerTestCase(test.TrialTestCase): self.assertEqual(log.AUDIT, l.level) -class VerboseLoggerTestCase(test.TrialTestCase): +class VerboseLoggerTestCase(test.TestCase): def setUp(self): super(VerboseLoggerTestCase, self).setUp() self.flags(default_log_levels=["nova.test=AUDIT"], verbose=True) diff --git a/nova/tests/test_middleware.py b/nova/tests/test_middleware.py index 0febf52d6..9d49167ba 100644 --- a/nova/tests/test_middleware.py +++ b/nova/tests/test_middleware.py @@ -38,7 +38,7 @@ def conditional_forbid(req): return 'OK' -class LockoutTestCase(test.TrialTestCase): +class LockoutTestCase(test.TestCase): """Test case for the Lockout middleware.""" def setUp(self): # pylint: disable-msg=C0103 super(LockoutTestCase, self).setUp() diff --git a/nova/tests/test_twistd.py b/nova/tests/test_twistd.py index 75007b9c8..ff8627c3b 100644 --- a/nova/tests/test_twistd.py +++ b/nova/tests/test_twistd.py @@ -28,7 +28,7 @@ from nova import test FLAGS = flags.FLAGS -class TwistdTestCase(test.TrialTestCase): +class TwistdTestCase(test.TestCase): def setUp(self): super(TwistdTestCase, self).setUp() self.Options = twistd.WrapTwistedOptions(twistd.TwistdServerOptions) From 3e4f89b504a4ad824870c168bcd354644a0860b1 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 14 Jan 2011 11:19:51 -0800 Subject: [PATCH 30/31] undo accidental removal of fake_flags --- nova/test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nova/test.py b/nova/test.py index a26b85b04..881baccd5 100644 --- a/nova/test.py +++ b/nova/test.py @@ -27,8 +27,6 @@ import unittest import mox import stubout -from twisted.internet import defer -from twisted.trial import unittest as trial_unittest from nova import context from nova import db @@ -36,6 +34,7 @@ from nova import fakerabbit from nova import flags from nova import rpc from nova.network import manager as network_manager +from nova.tests import fake_flags FLAGS = flags.FLAGS From acc246907f357ae0157f669769719ab018123b05 Mon Sep 17 00:00:00 2001 From: Andy Smith Date: Fri, 14 Jan 2011 17:44:47 -0800 Subject: [PATCH 31/31] pep8 --- nova/tests/test_console.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nova/tests/test_console.py b/nova/tests/test_console.py index 69e2109e6..85bf94458 100644 --- a/nova/tests/test_console.py +++ b/nova/tests/test_console.py @@ -130,4 +130,3 @@ class ConsoleTestCase(test.TestCase): self.context, console_id) db.instance_destroy(self.context, instance_id) -