Uncommitted changes using the wrong author, and re-committing under the correct author

This commit is contained in:
Ed Leafe
2011-02-17 22:09:26 +00:00
17 changed files with 328 additions and 74 deletions

View File

@@ -1,35 +1,43 @@
# Format is: # Format is:
# <preferred e-mail> <other e-mail> # <preferred e-mail> <other e-mail 1>
<code@term.ie> <github@anarkystic.com> # <preferred e-mail> <other e-mail 2>
<code@term.ie> <termie@preciousroy.local>
<Armando.Migliaccio@eu.citrix.com> <armando.migliaccio@citrix.com>
<matt.dietz@rackspace.com> <matthewdietz@Matthew-Dietzs-MacBook-Pro.local>
<matt.dietz@rackspace.com> <mdietz@openstack>
<cbehrens@codestud.com> <chris.behrens@rackspace.com>
<devin.carlen@gmail.com> <devcamcar@illian.local>
<ewan.mellor@citrix.com> <emellor@silver>
<jaypipes@gmail.com> <jpipes@serialcoder>
<anotherjesse@gmail.com> <jesse@dancelamb> <anotherjesse@gmail.com> <jesse@dancelamb>
<anotherjesse@gmail.com> <jesse@gigantor.local> <anotherjesse@gmail.com> <jesse@gigantor.local>
<anotherjesse@gmail.com> <jesse@ubuntu> <anotherjesse@gmail.com> <jesse@ubuntu>
<jmckenty@gmail.com> <jmckenty@yyj-dhcp171.corp.flock.com> <ant@openstack.org> <amesserl@rackspace.com>
<Armando.Migliaccio@eu.citrix.com> <armando.migliaccio@citrix.com>
<brian.lamar@rackspace.com> <brian.lamar@gmail.com>
<bschott@isi.edu> <bfschott@gmail.com>
<cbehrens@codestud.com> <chris.behrens@rackspace.com>
<chiradeep@cloud.com> <chiradeep@chiradeep-lt2>
<code@term.ie> <github@anarkystic.com>
<code@term.ie> <termie@preciousroy.local>
<corywright@gmail.com> <cory.wright@rackspace.com>
<devin.carlen@gmail.com> <devcamcar@illian.local>
<ewan.mellor@citrix.com> <emellor@silver>
<jaypipes@gmail.com> <jpipes@serialcoder>
<jmckenty@gmail.com> <jmckenty@joshua-mckentys-macbook-pro.local> <jmckenty@gmail.com> <jmckenty@joshua-mckentys-macbook-pro.local>
<jmckenty@gmail.com> <jmckenty@yyj-dhcp171.corp.flock.com>
<jmckenty@gmail.com> <joshua.mckenty@nasa.gov> <jmckenty@gmail.com> <joshua.mckenty@nasa.gov>
<justin@fathomdb.com> <justinsb@justinsb-desktop> <justin@fathomdb.com> <justinsb@justinsb-desktop>
<masumotok@nttdata.co.jp> <root@openstack2-api> <justin@fathomdb.com> <superstack@superstack.org>
<masumotok@nttdata.co.jp> Masumoto<masumotok@nttdata.co.jp> <masumotok@nttdata.co.jp> Masumoto<masumotok@nttdata.co.jp>
<masumotok@nttdata.co.jp> <root@openstack2-api>
<matt.dietz@rackspace.com> <matthewdietz@Matthew-Dietzs-MacBook-Pro.local>
<matt.dietz@rackspace.com> <mdietz@openstack>
<mordred@inaugust.com> <mordred@hudson> <mordred@inaugust.com> <mordred@hudson>
<paul@openstack.org> <pvoccio@castor.local>
<paul@openstack.org> <paul.voccio@rackspace.com> <paul@openstack.org> <paul.voccio@rackspace.com>
<paul@openstack.org> <pvoccio@castor.local>
<rconradharris@gmail.com> <rick.harris@rackspace.com>
<rlane@wikimedia.org> <laner@controller>
<sleepsonthefloor@gmail.com> <root@tonbuntu>
<soren.hansen@rackspace.com> <soren@linux2go.dk> <soren.hansen@rackspace.com> <soren@linux2go.dk>
<todd@ansolabs.com> <todd@lapex> <todd@ansolabs.com> <todd@lapex>
<todd@ansolabs.com> <todd@rubidine.com> <todd@ansolabs.com> <todd@rubidine.com>
<vishvananda@gmail.com> <vishvananda@yahoo.com> <tushar.vitthal.patil@gmail.com> <tpatil@vertex.co.in>
<ueno.nachi@lab.ntt.co.jp> <nati.ueno@gmail.com>
<ueno.nachi@lab.ntt.co.jp> <nova@u4>
<ueno.nachi@lab.ntt.co.jp> <openstack@lab.ntt.co.jp>
<vishvananda@gmail.com> <root@mirror.nasanebula.net> <vishvananda@gmail.com> <root@mirror.nasanebula.net>
<vishvananda@gmail.com> <root@ubuntu> <vishvananda@gmail.com> <root@ubuntu>
<sleepsonthefloor@gmail.com> <root@tonbuntu> <vishvananda@gmail.com> <vishvananda@yahoo.com>
<rlane@wikimedia.org> <laner@controller>
<rconradharris@gmail.com> <rick.harris@rackspace.com>
<corywright@gmail.com> <cory.wright@rackspace.com>
<ant@openstack.org> <amesserl@rackspace.com>
<chiradeep@cloud.com> <chiradeep@chiradeep-lt2>

14
Authors
View File

@@ -3,12 +3,17 @@ Anne Gentle <anne@openstack.org>
Anthony Young <sleepsonthefloor@gmail.com> Anthony Young <sleepsonthefloor@gmail.com>
Antony Messerli <ant@openstack.org> Antony Messerli <ant@openstack.org>
Armando Migliaccio <Armando.Migliaccio@eu.citrix.com> Armando Migliaccio <Armando.Migliaccio@eu.citrix.com>
Bilal Akhtar <bilalakhtar@ubuntu.com>
Brian Lamar <brian.lamar@rackspace.com>
Brian Schott <bschott@isi.edu>
Brian Waldon <brian.waldon@rackspace.com>
Chiradeep Vittal <chiradeep@cloud.com> Chiradeep Vittal <chiradeep@cloud.com>
Chmouel Boudjnah <chmouel@chmouel.com> Chmouel Boudjnah <chmouel@chmouel.com>
Chris Behrens <cbehrens@codestud.com> Chris Behrens <cbehrens@codestud.com>
Christian Berendt <berendt@b1-systems.de>
Cory Wright <corywright@gmail.com> Cory Wright <corywright@gmail.com>
David Pravec <David.Pravec@danix.org>
Dan Prince <dan.prince@rackspace.com> Dan Prince <dan.prince@rackspace.com>
David Pravec <David.Pravec@danix.org>
Dean Troyer <dtroyer@gmail.com> Dean Troyer <dtroyer@gmail.com>
Devin Carlen <devin.carlen@gmail.com> Devin Carlen <devin.carlen@gmail.com>
Ed Leafe <ed@leafe.com> Ed Leafe <ed@leafe.com>
@@ -39,8 +44,10 @@ Monsyne Dragon <mdragon@rackspace.com>
Monty Taylor <mordred@inaugust.com> Monty Taylor <mordred@inaugust.com>
MORITA Kazutaka <morita.kazutaka@gmail.com> MORITA Kazutaka <morita.kazutaka@gmail.com>
Muneyuki Noguchi <noguchimn@nttdata.co.jp> Muneyuki Noguchi <noguchimn@nttdata.co.jp>
Nachi Ueno <ueno.nachi@lab.ntt.co.jp> <openstack@lab.ntt.co.jp> <nati.ueno@gmail.com> <nova@u4> Nachi Ueno <ueno.nachi@lab.ntt.co.jp>
Naveed Massjouni <naveed.massjouni@rackspace.com>
Paul Voccio <paul@openstack.org> Paul Voccio <paul@openstack.org>
Ricardo Carrillo Cruz <emaildericky@gmail.com>
Rick Clark <rick@openstack.org> Rick Clark <rick@openstack.org>
Rick Harris <rconradharris@gmail.com> Rick Harris <rconradharris@gmail.com>
Rob Kost <kost@isi.edu> Rob Kost <kost@isi.edu>
@@ -52,7 +59,8 @@ Soren Hansen <soren.hansen@rackspace.com>
Thierry Carrez <thierry@openstack.org> Thierry Carrez <thierry@openstack.org>
Todd Willey <todd@ansolabs.com> Todd Willey <todd@ansolabs.com>
Trey Morris <trey.morris@rackspace.com> Trey Morris <trey.morris@rackspace.com>
Tushar Patil <tushar.vitthal.patil@gmail.com> <tpatil@vertex.co.in> Tushar Patil <tushar.vitthal.patil@gmail.com>
Vasiliy Shlykov <vash@vasiliyshlykov.org>
Vishvananda Ishaya <vishvananda@gmail.com> Vishvananda Ishaya <vishvananda@gmail.com>
Youcef Laribi <Youcef.Laribi@eu.citrix.com> Youcef Laribi <Youcef.Laribi@eu.citrix.com>
Zhixue Wu <Zhixue.Wu@citrix.com> Zhixue Wu <Zhixue.Wu@citrix.com>

19
HACKING
View File

@@ -47,3 +47,22 @@ Human Alphabetical Order Examples
from nova.auth import users from nova.auth import users
from nova.endpoint import api from nova.endpoint import api
from nova.endpoint import cloud from nova.endpoint import cloud
Docstrings
----------
"""Summary of the function, class or method, less than 80 characters.
New paragraph after newline that explains in more detail any general
information about the function, class or method. After this, if defining
parameters and return types use the Sphinx format. After that an extra
newline then close the quotations.
When writing the docstring for a class, an extra line should be placed
after the closing quotations. For more in-depth explanations for these
decisions see http://www.python.org/dev/peps/pep-0257/
:param foo: the foo parameter
:param bar: the bar parameter
:returns: description of the return value
"""

View File

@@ -6,14 +6,23 @@ graft doc
graft smoketests graft smoketests
graft tools graft tools
graft etc graft etc
graft bzrplugins
graft contrib
graft po
graft plugins
include nova/api/openstack/notes.txt include nova/api/openstack/notes.txt
include nova/auth/*.schema
include nova/auth/novarc.template include nova/auth/novarc.template
include nova/auth/opendj.sh
include nova/auth/slap.sh include nova/auth/slap.sh
include nova/cloudpipe/bootscript.sh include nova/cloudpipe/bootscript.sh
include nova/cloudpipe/client.ovpn.template include nova/cloudpipe/client.ovpn.template
include nova/cloudpipe/bootscript.template
include nova/compute/fakevirtinstance.xml include nova/compute/fakevirtinstance.xml
include nova/compute/interfaces.template include nova/compute/interfaces.template
include nova/console/xvp.conf.template
include nova/db/sqlalchemy/migrate_repo/migrate.cfg include nova/db/sqlalchemy/migrate_repo/migrate.cfg
include nova/db/sqlalchemy/migrate_repo/README
include nova/virt/interfaces.template include nova/virt/interfaces.template
include nova/virt/libvirt*.xml.template include nova/virt/libvirt*.xml.template
include nova/tests/CA/ include nova/tests/CA/
@@ -25,6 +34,7 @@ include nova/tests/bundle/1mb.manifest.xml
include nova/tests/bundle/1mb.no_kernel_or_ramdisk.manifest.xml include nova/tests/bundle/1mb.no_kernel_or_ramdisk.manifest.xml
include nova/tests/bundle/1mb.part.0 include nova/tests/bundle/1mb.part.0
include nova/tests/bundle/1mb.part.1 include nova/tests/bundle/1mb.part.1
include nova/tests/db/nova.austin.sqlite
include plugins/xenapi/README include plugins/xenapi/README
include plugins/xenapi/etc/xapi.d/plugins/objectstore include plugins/xenapi/etc/xapi.d/plugins/objectstore
include plugins/xenapi/etc/xapi.d/plugins/pluginlib_nova.py include plugins/xenapi/etc/xapi.d/plugins/pluginlib_nova.py

View File

@@ -433,6 +433,37 @@ class ProjectCommands(object):
"nova-api server on this host.") "nova-api server on this host.")
class FixedIpCommands(object):
"""Class for managing fixed ip."""
def list(self, host=None):
"""Lists all fixed ips (optionally by host) arguments: [host]"""
ctxt = context.get_admin_context()
if host == None:
fixed_ips = db.fixed_ip_get_all(ctxt)
else:
fixed_ips = db.fixed_ip_get_all_by_host(ctxt, host)
print "%-18s\t%-15s\t%-17s\t%-15s\t%s" % (_('network'),
_('IP address'),
_('MAC address'),
_('hostname'),
_('host'))
for fixed_ip in fixed_ips:
hostname = None
host = None
mac_address = None
if fixed_ip['instance']:
instance = fixed_ip['instance']
hostname = instance['hostname']
host = instance['host']
mac_address = instance['mac_address']
print "%-18s\t%-15s\t%-17s\t%-15s\t%s" % (
fixed_ip['network']['cidr'],
fixed_ip['address'],
mac_address, hostname, host)
class FloatingIpCommands(object): class FloatingIpCommands(object):
"""Class for managing floating ip.""" """Class for managing floating ip."""
@@ -472,8 +503,8 @@ class NetworkCommands(object):
"""Class for managing networks.""" """Class for managing networks."""
def create(self, fixed_range=None, num_networks=None, def create(self, fixed_range=None, num_networks=None,
network_size=None, vlan_start=None, vpn_start=None, network_size=None, vlan_start=None,
fixed_range_v6=None): vpn_start=None, fixed_range_v6=None, label='public'):
"""Creates fixed ips for host by range """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], [network_size=FLAG], [vlan_start=FLAG],
@@ -495,9 +526,22 @@ class NetworkCommands(object):
cidr=fixed_range, cidr=fixed_range,
num_networks=int(num_networks), num_networks=int(num_networks),
network_size=int(network_size), network_size=int(network_size),
cidr_v6=fixed_range_v6,
vlan_start=int(vlan_start), vlan_start=int(vlan_start),
vpn_start=int(vpn_start)) vpn_start=int(vpn_start),
cidr_v6=fixed_range_v6,
label=label)
def list(self):
"""List all created networks"""
print "%-18s\t%-15s\t%-15s\t%-15s" % (_('network'),
_('netmask'),
_('start address'),
'DNS')
for network in db.network_get_all(context.get_admin_context()):
print "%-18s\t%-15s\t%-15s\t%-15s" % (network.cidr,
network.netmask,
network.dhcp_start,
network.dns)
class ServiceCommands(object): class ServiceCommands(object):
@@ -579,6 +623,13 @@ class VolumeCommands(object):
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
volume = db.volume_get(ctxt, param2id(volume_id)) volume = db.volume_get(ctxt, param2id(volume_id))
host = volume['host'] host = volume['host']
if not host:
print "Volume not yet assigned to host."
print "Deleting volume from database and skipping rpc."
db.volume_destroy(ctxt, param2id(volume_id))
return
if volume['status'] == 'in-use': if volume['status'] == 'in-use':
print "Volume is in-use." print "Volume is in-use."
print "Detach volume from instance and then try again." print "Detach volume from instance and then try again."
@@ -615,6 +666,7 @@ CATEGORIES = [
('role', RoleCommands), ('role', RoleCommands),
('shell', ShellCommands), ('shell', ShellCommands),
('vpn', VpnCommands), ('vpn', VpnCommands),
('fixed', FixedIpCommands),
('floating', FloatingIpCommands), ('floating', FloatingIpCommands),
('network', NetworkCommands), ('network', NetworkCommands),
('service', ServiceCommands), ('service', ServiceCommands),

View File

@@ -1826,7 +1826,7 @@ msgstr ""
#: nova/virt/xenapi/vm_utils.py:290 #: nova/virt/xenapi/vm_utils.py:290
#, python-format #, python-format
msgid "PV Kernel in VDI:%d" msgid "PV Kernel in VDI:%s"
msgstr "" msgstr ""
#: nova/virt/xenapi/vm_utils.py:318 #: nova/virt/xenapi/vm_utils.py:318

View File

@@ -21,6 +21,7 @@ Nova User API client library.
import base64 import base64
import boto import boto
import boto.exception
import httplib import httplib
from boto.ec2.regioninfo import RegionInfo from boto.ec2.regioninfo import RegionInfo
@@ -288,10 +289,14 @@ class NovaAdminClient(object):
def get_user(self, name): def get_user(self, name):
"""Grab a single user by name.""" """Grab a single user by name."""
user = self.apiconn.get_object('DescribeUser', {'Name': name}, try:
return self.apiconn.get_object('DescribeUser',
{'Name': name},
UserInfo) UserInfo)
if user.username != None: except boto.exception.BotoServerError, e:
return user if e.status == 400 and e.error_code == 'NotFound':
return None
raise
def has_user(self, username): def has_user(self, username):
"""Determine if user exists.""" """Determine if user exists."""
@@ -376,6 +381,13 @@ class NovaAdminClient(object):
'MemberUsers': member_users} 'MemberUsers': member_users}
return self.apiconn.get_object('RegisterProject', params, ProjectInfo) return self.apiconn.get_object('RegisterProject', params, ProjectInfo)
def modify_project(self, projectname, manager_user=None, description=None):
"""Modifies an existing project."""
params = {'Name': projectname,
'ManagerUser': manager_user,
'Description': description}
return self.apiconn.get_status('ModifyProject', params)
def delete_project(self, projectname): def delete_project(self, projectname):
"""Permanently deletes the specified project.""" """Permanently deletes the specified project."""
return self.apiconn.get_object('DeregisterProject', return self.apiconn.get_object('DeregisterProject',

View File

@@ -74,6 +74,25 @@ LOG = logging.getLogger("nova.ldapdriver")
# in which we may want to change the interface a bit more. # in which we may want to change the interface a bit more.
def _clean(attr):
"""Clean attr for insertion into ldap"""
if attr is None:
return None
if type(attr) is unicode:
return str(attr)
return attr
def sanitize(fn):
"""Decorator to sanitize all args"""
def _wrapped(self, *args, **kwargs):
args = [_clean(x) for x in args]
kwargs = dict((k, _clean(v)) for (k, v) in kwargs)
return fn(self, *args, **kwargs)
_wrapped.func_name = fn.func_name
return _wrapped
class LdapDriver(object): class LdapDriver(object):
"""Ldap Auth driver """Ldap Auth driver
@@ -106,23 +125,27 @@ class LdapDriver(object):
self.conn.unbind_s() self.conn.unbind_s()
return False return False
@sanitize
def get_user(self, uid): def get_user(self, uid):
"""Retrieve user by id""" """Retrieve user by id"""
attr = self.__get_ldap_user(uid) attr = self.__get_ldap_user(uid)
return self.__to_user(attr) return self.__to_user(attr)
@sanitize
def get_user_from_access_key(self, access): def get_user_from_access_key(self, access):
"""Retrieve user by access key""" """Retrieve user by access key"""
query = '(accessKey=%s)' % access query = '(accessKey=%s)' % access
dn = FLAGS.ldap_user_subtree dn = FLAGS.ldap_user_subtree
return self.__to_user(self.__find_object(dn, query)) return self.__to_user(self.__find_object(dn, query))
@sanitize
def get_project(self, pid): def get_project(self, pid):
"""Retrieve project by id""" """Retrieve project by id"""
dn = self.__project_to_dn(pid) dn = self.__project_to_dn(pid)
attr = self.__find_object(dn, LdapDriver.project_pattern) attr = self.__find_object(dn, LdapDriver.project_pattern)
return self.__to_project(attr) return self.__to_project(attr)
@sanitize
def get_users(self): def get_users(self):
"""Retrieve list of users""" """Retrieve list of users"""
attrs = self.__find_objects(FLAGS.ldap_user_subtree, attrs = self.__find_objects(FLAGS.ldap_user_subtree,
@@ -134,6 +157,7 @@ class LdapDriver(object):
users.append(user) users.append(user)
return users return users
@sanitize
def get_projects(self, uid=None): def get_projects(self, uid=None):
"""Retrieve list of projects""" """Retrieve list of projects"""
pattern = LdapDriver.project_pattern pattern = LdapDriver.project_pattern
@@ -143,6 +167,7 @@ class LdapDriver(object):
pattern) pattern)
return [self.__to_project(attr) for attr in attrs] return [self.__to_project(attr) for attr in attrs]
@sanitize
def create_user(self, name, access_key, secret_key, is_admin): def create_user(self, name, access_key, secret_key, is_admin):
"""Create a user""" """Create a user"""
if self.__user_exists(name): if self.__user_exists(name):
@@ -196,6 +221,7 @@ class LdapDriver(object):
self.conn.add_s(self.__uid_to_dn(name), attr) self.conn.add_s(self.__uid_to_dn(name), attr)
return self.__to_user(dict(attr)) return self.__to_user(dict(attr))
@sanitize
def create_project(self, name, manager_uid, def create_project(self, name, manager_uid,
description=None, member_uids=None): description=None, member_uids=None):
"""Create a project""" """Create a project"""
@@ -231,6 +257,7 @@ class LdapDriver(object):
self.conn.add_s(dn, attr) self.conn.add_s(dn, attr)
return self.__to_project(dict(attr)) return self.__to_project(dict(attr))
@sanitize
def modify_project(self, project_id, manager_uid=None, description=None): def modify_project(self, project_id, manager_uid=None, description=None):
"""Modify an existing project""" """Modify an existing project"""
if not manager_uid and not description: if not manager_uid and not description:
@@ -249,21 +276,25 @@ class LdapDriver(object):
dn = self.__project_to_dn(project_id) dn = self.__project_to_dn(project_id)
self.conn.modify_s(dn, attr) self.conn.modify_s(dn, attr)
@sanitize
def add_to_project(self, uid, project_id): def add_to_project(self, uid, project_id):
"""Add user to project""" """Add user to project"""
dn = self.__project_to_dn(project_id) dn = self.__project_to_dn(project_id)
return self.__add_to_group(uid, dn) return self.__add_to_group(uid, dn)
@sanitize
def remove_from_project(self, uid, project_id): def remove_from_project(self, uid, project_id):
"""Remove user from project""" """Remove user from project"""
dn = self.__project_to_dn(project_id) dn = self.__project_to_dn(project_id)
return self.__remove_from_group(uid, dn) return self.__remove_from_group(uid, dn)
@sanitize
def is_in_project(self, uid, project_id): def is_in_project(self, uid, project_id):
"""Check if user is in project""" """Check if user is in project"""
dn = self.__project_to_dn(project_id) dn = self.__project_to_dn(project_id)
return self.__is_in_group(uid, dn) return self.__is_in_group(uid, dn)
@sanitize
def has_role(self, uid, role, project_id=None): def has_role(self, uid, role, project_id=None):
"""Check if user has role """Check if user has role
@@ -273,6 +304,7 @@ class LdapDriver(object):
role_dn = self.__role_to_dn(role, project_id) role_dn = self.__role_to_dn(role, project_id)
return self.__is_in_group(uid, role_dn) return self.__is_in_group(uid, role_dn)
@sanitize
def add_role(self, uid, role, project_id=None): def add_role(self, uid, role, project_id=None):
"""Add role for user (or user and project)""" """Add role for user (or user and project)"""
role_dn = self.__role_to_dn(role, project_id) role_dn = self.__role_to_dn(role, project_id)
@@ -283,11 +315,13 @@ class LdapDriver(object):
else: else:
return self.__add_to_group(uid, role_dn) return self.__add_to_group(uid, role_dn)
@sanitize
def remove_role(self, uid, role, project_id=None): def remove_role(self, uid, role, project_id=None):
"""Remove role for user (or user and project)""" """Remove role for user (or user and project)"""
role_dn = self.__role_to_dn(role, project_id) role_dn = self.__role_to_dn(role, project_id)
return self.__remove_from_group(uid, role_dn) return self.__remove_from_group(uid, role_dn)
@sanitize
def get_user_roles(self, uid, project_id=None): def get_user_roles(self, uid, project_id=None):
"""Retrieve list of roles for user (or user and project)""" """Retrieve list of roles for user (or user and project)"""
if project_id is None: if project_id is None:
@@ -307,6 +341,7 @@ class LdapDriver(object):
roles = self.__find_objects(project_dn, query) roles = self.__find_objects(project_dn, query)
return [role['cn'][0] for role in roles] return [role['cn'][0] for role in roles]
@sanitize
def delete_user(self, uid): def delete_user(self, uid):
"""Delete a user""" """Delete a user"""
if not self.__user_exists(uid): if not self.__user_exists(uid):
@@ -332,12 +367,14 @@ class LdapDriver(object):
# Delete entry # Delete entry
self.conn.delete_s(self.__uid_to_dn(uid)) self.conn.delete_s(self.__uid_to_dn(uid))
@sanitize
def delete_project(self, project_id): def delete_project(self, project_id):
"""Delete a project""" """Delete a project"""
project_dn = self.__project_to_dn(project_id) project_dn = self.__project_to_dn(project_id)
self.__delete_roles(project_dn) self.__delete_roles(project_dn)
self.__delete_group(project_dn) self.__delete_group(project_dn)
@sanitize
def modify_user(self, uid, access_key=None, secret_key=None, admin=None): def modify_user(self, uid, access_key=None, secret_key=None, admin=None):
"""Modify an existing user""" """Modify an existing user"""
if not access_key and not secret_key and admin is None: if not access_key and not secret_key and admin is None:

View File

@@ -208,7 +208,7 @@ def _get_my_ip():
(addr, port) = csock.getsockname() (addr, port) = csock.getsockname()
csock.close() csock.close()
return addr return addr
except socket.gaierror as ex: except socket.error as ex:
return "127.0.0.1" return "127.0.0.1"
@@ -282,12 +282,14 @@ DEFINE_integer('auth_token_ttl', 3600, 'Seconds for auth tokens to linger')
DEFINE_string('state_path', os.path.join(os.path.dirname(__file__), '../'), DEFINE_string('state_path', os.path.join(os.path.dirname(__file__), '../'),
"Top-level directory for maintaining nova's state") "Top-level directory for maintaining nova's state")
DEFINE_string('logdir', None, 'output to a per-service log file in named '
'directory')
DEFINE_string('sql_connection', DEFINE_string('sql_connection',
'sqlite:///$state_path/nova.sqlite', 'sqlite:///$state_path/nova.sqlite',
'connection string for sql database') 'connection string for sql database')
DEFINE_string('sql_idle_timeout', DEFINE_integer('sql_idle_timeout',
'3600', 3600,
'timeout for idle sql database connections') 'timeout for idle sql database connections')
DEFINE_integer('sql_max_retries', 12, 'sql connection attempts') DEFINE_integer('sql_max_retries', 12, 'sql connection attempts')
DEFINE_integer('sql_retry_interval', 10, 'sql connection retry interval') DEFINE_integer('sql_retry_interval', 10, 'sql connection retry interval')

View File

@@ -28,9 +28,12 @@ It also allows setting of formatting information through flags.
import cStringIO import cStringIO
import inspect
import json import json
import logging import logging
import logging.handlers import logging.handlers
import os
import sys
import traceback import traceback
from nova import flags from nova import flags
@@ -91,7 +94,7 @@ critical = logging.critical
log = logging.log log = logging.log
# handlers # handlers
StreamHandler = logging.StreamHandler StreamHandler = logging.StreamHandler
FileHandler = logging.FileHandler RotatingFileHandler = logging.handlers.RotatingFileHandler
# logging.SysLogHandler is nicer than logging.logging.handler.SysLogHandler. # logging.SysLogHandler is nicer than logging.logging.handler.SysLogHandler.
SysLogHandler = logging.handlers.SysLogHandler SysLogHandler = logging.handlers.SysLogHandler
@@ -110,6 +113,18 @@ def _dictify_context(context):
return context return context
def _get_binary_name():
return os.path.basename(inspect.stack()[-1][1])
def get_log_file_path(binary=None):
if FLAGS.logfile:
return FLAGS.logfile
if FLAGS.logdir:
binary = binary or _get_binary_name()
return '%s.log' % (os.path.join(FLAGS.logdir, binary),)
def basicConfig(): def basicConfig():
logging.basicConfig() logging.basicConfig()
for handler in logging.root.handlers: for handler in logging.root.handlers:
@@ -122,8 +137,9 @@ def basicConfig():
syslog = SysLogHandler(address='/dev/log') syslog = SysLogHandler(address='/dev/log')
syslog.setFormatter(_formatter) syslog.setFormatter(_formatter)
logging.root.addHandler(syslog) logging.root.addHandler(syslog)
if FLAGS.logfile: logpath = get_log_file_path()
logfile = FileHandler(FLAGS.logfile) if logpath:
logfile = RotatingFileHandler(logpath)
logfile.setFormatter(_formatter) logfile.setFormatter(_formatter)
logging.root.addHandler(logfile) logging.root.addHandler(logfile)
@@ -191,6 +207,12 @@ class NovaLogger(logging.Logger):
kwargs.pop('exc_info') kwargs.pop('exc_info')
self.error(message, **kwargs) self.error(message, **kwargs)
def handle_exception(type, value, tb):
logging.root.critical(str(value), exc_info=(type, value, tb))
sys.excepthook = handle_exception
logging.setLoggerClass(NovaLogger) logging.setLoggerClass(NovaLogger)

View File

@@ -29,6 +29,7 @@ import uuid
from carrot import connection as carrot_connection from carrot import connection as carrot_connection
from carrot import messaging from carrot import messaging
from eventlet import greenpool
from eventlet import greenthread from eventlet import greenthread
from nova import context from nova import context
@@ -42,11 +43,13 @@ from nova import utils
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.rpc') LOG = logging.getLogger('nova.rpc')
flags.DEFINE_integer('rpc_thread_pool_size', 1024, 'Size of RPC thread pool')
class Connection(carrot_connection.BrokerConnection): class Connection(carrot_connection.BrokerConnection):
"""Connection instance object""" """Connection instance object"""
@classmethod @classmethod
def instance(cls, new=False): def instance(cls, new=True):
"""Returns the instance""" """Returns the instance"""
if new or not hasattr(cls, '_instance'): if new or not hasattr(cls, '_instance'):
params = dict(hostname=FLAGS.rabbit_host, params = dict(hostname=FLAGS.rabbit_host,
@@ -155,11 +158,15 @@ class AdapterConsumer(TopicConsumer):
def __init__(self, connection=None, topic="broadcast", proxy=None): def __init__(self, connection=None, topic="broadcast", proxy=None):
LOG.debug(_('Initing the Adapter Consumer for %s') % topic) LOG.debug(_('Initing the Adapter Consumer for %s') % topic)
self.proxy = proxy self.proxy = proxy
self.pool = greenpool.GreenPool(FLAGS.rpc_thread_pool_size)
super(AdapterConsumer, self).__init__(connection=connection, super(AdapterConsumer, self).__init__(connection=connection,
topic=topic) topic=topic)
def receive(self, *args, **kwargs):
self.pool.spawn_n(self._receive, *args, **kwargs)
@exception.wrap_exception @exception.wrap_exception
def receive(self, message_data, message): def _receive(self, message_data, message):
"""Magically looks for a method on the proxy object and calls it """Magically looks for a method on the proxy object and calls it
Message data should be a dictionary with two keys: Message data should be a dictionary with two keys:
@@ -246,7 +253,7 @@ def msg_reply(msg_id, reply=None, failure=None):
LOG.error(_("Returning exception %s to caller"), message) LOG.error(_("Returning exception %s to caller"), message)
LOG.error(tb) LOG.error(tb)
failure = (failure[0].__name__, str(failure[1]), tb) failure = (failure[0].__name__, str(failure[1]), tb)
conn = Connection.instance(True) conn = Connection.instance()
publisher = DirectPublisher(connection=conn, msg_id=msg_id) publisher = DirectPublisher(connection=conn, msg_id=msg_id)
try: try:
publisher.send({'result': reply, 'failure': failure}) publisher.send({'result': reply, 'failure': failure})
@@ -319,7 +326,7 @@ def call(context, topic, msg):
self.result = data['result'] self.result = data['result']
wait_msg = WaitMessage() wait_msg = WaitMessage()
conn = Connection.instance(True) conn = Connection.instance()
consumer = DirectConsumer(connection=conn, msg_id=msg_id) consumer = DirectConsumer(connection=conn, msg_id=msg_id)
consumer.register_callback(wait_msg) consumer.register_callback(wait_msg)

View File

@@ -248,11 +248,9 @@ class ApiEc2TestCase(test.TestCase):
self.mox.ReplayAll() self.mox.ReplayAll()
rv = self.ec2.get_all_security_groups() 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 group = [grp for grp in rv if grp.name == security_group_name][0]
# be good enough for that.
for group in rv:
if group.name == security_group_name:
self.assertEquals(len(group.rules), 1) self.assertEquals(len(group.rules), 1)
self.assertEquals(int(group.rules[0].from_port), 80) self.assertEquals(int(group.rules[0].from_port), 80)
self.assertEquals(int(group.rules[0].to_port), 81) self.assertEquals(int(group.rules[0].to_port), 81)
@@ -314,11 +312,8 @@ class ApiEc2TestCase(test.TestCase):
self.mox.ReplayAll() self.mox.ReplayAll()
rv = self.ec2.get_all_security_groups() 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 group = [grp for grp in rv if grp.name == security_group_name][0]
# be good enough for that.
for group in rv:
if group.name == security_group_name:
self.assertEquals(len(group.rules), 1) self.assertEquals(len(group.rules), 1)
self.assertEquals(int(group.rules[0].from_port), 80) self.assertEquals(int(group.rules[0].from_port), 80)
self.assertEquals(int(group.rules[0].to_port), 81) self.assertEquals(int(group.rules[0].to_port), 81)

View File

@@ -49,7 +49,7 @@ class ComputeTestCase(test.TestCase):
self.manager = manager.AuthManager() self.manager = manager.AuthManager()
self.user = self.manager.create_user('fake', 'fake', 'fake') self.user = self.manager.create_user('fake', 'fake', 'fake')
self.project = self.manager.create_project('fake', 'fake', 'fake') self.project = self.manager.create_project('fake', 'fake', 'fake')
self.context = context.get_admin_context() self.context = context.RequestContext('fake', 'fake', False)
def tearDown(self): def tearDown(self):
self.manager.delete_user(self.user) self.manager.delete_user(self.user)
@@ -69,6 +69,13 @@ class ComputeTestCase(test.TestCase):
inst['ami_launch_index'] = 0 inst['ami_launch_index'] = 0
return db.instance_create(self.context, inst)['id'] return db.instance_create(self.context, inst)['id']
def _create_group(self):
values = {'name': 'testgroup',
'description': 'testgroup',
'user_id': self.user.id,
'project_id': self.project.id}
return db.security_group_create(self.context, values)
def test_create_instance_defaults_display_name(self): def test_create_instance_defaults_display_name(self):
"""Verify that an instance cannot be created without a display_name.""" """Verify that an instance cannot be created without a display_name."""
cases = [dict(), dict(display_name=None)] cases = [dict(), dict(display_name=None)]
@@ -82,23 +89,55 @@ class ComputeTestCase(test.TestCase):
def test_create_instance_associates_security_groups(self): def test_create_instance_associates_security_groups(self):
"""Make sure create associates security groups""" """Make sure create associates security groups"""
values = {'name': 'default', group = self._create_group()
'description': 'default',
'user_id': self.user.id,
'project_id': self.project.id}
group = db.security_group_create(self.context, values)
ref = self.compute_api.create( ref = self.compute_api.create(
self.context, self.context,
instance_type=FLAGS.default_instance_type, instance_type=FLAGS.default_instance_type,
image_id=None, image_id=None,
security_group=['default']) security_group=['testgroup'])
try: try:
self.assertEqual(len(db.security_group_get_by_instance( self.assertEqual(len(db.security_group_get_by_instance(
self.context, ref[0]['id'])), 1) self.context, ref[0]['id'])), 1)
group = db.security_group_get(self.context, group['id'])
self.assert_(len(group.instances) == 1)
finally: finally:
db.security_group_destroy(self.context, group['id']) db.security_group_destroy(self.context, group['id'])
db.instance_destroy(self.context, ref[0]['id']) db.instance_destroy(self.context, ref[0]['id'])
def test_destroy_instance_disassociates_security_groups(self):
"""Make sure destroying disassociates security groups"""
group = self._create_group()
ref = self.compute_api.create(
self.context,
instance_type=FLAGS.default_instance_type,
image_id=None,
security_group=['testgroup'])
try:
db.instance_destroy(self.context, ref[0]['id'])
group = db.security_group_get(self.context, group['id'])
self.assert_(len(group.instances) == 0)
finally:
db.security_group_destroy(self.context, group['id'])
def test_destroy_security_group_disassociates_instances(self):
"""Make sure destroying security groups disassociates instances"""
group = self._create_group()
ref = self.compute_api.create(
self.context,
instance_type=FLAGS.default_instance_type,
image_id=None,
security_group=['testgroup'])
try:
db.security_group_destroy(self.context, group['id'])
group = db.security_group_get(context.get_admin_context(
read_deleted=True), group['id'])
self.assert_(len(group.instances) == 0)
finally:
db.instance_destroy(self.context, ref[0]['id'])
def test_run_terminate(self): def test_run_terminate(self):
"""Make sure it is possible to run and terminate instance""" """Make sure it is possible to run and terminate instance"""
instance_id = self._create_instance() instance_id = self._create_instance()
@@ -163,6 +202,14 @@ class ComputeTestCase(test.TestCase):
self.compute.set_admin_password(self.context, instance_id) self.compute.set_admin_password(self.context, instance_id)
self.compute.terminate_instance(self.context, instance_id) self.compute.terminate_instance(self.context, instance_id)
def test_inject_file(self):
"""Ensure we can write a file to an instance"""
instance_id = self._create_instance()
self.compute.run_instance(self.context, instance_id)
self.compute.inject_file(self.context, instance_id, "/tmp/test",
"File Contents")
self.compute.terminate_instance(self.context, instance_id)
def test_snapshot(self): def test_snapshot(self):
"""Ensure instance can be snapshotted""" """Ensure instance can be snapshotted"""
instance_id = self._create_instance() instance_id = self._create_instance()

View File

@@ -46,6 +46,27 @@ class RootLoggerTestCase(test.TestCase):
self.assert_(True) # didn't raise exception self.assert_(True) # didn't raise exception
class LogHandlerTestCase(test.TestCase):
def test_log_path_logdir(self):
self.flags(logdir='/some/path')
self.assertEquals(log.get_log_file_path(binary='foo-bar'),
'/some/path/foo-bar.log')
def test_log_path_logfile(self):
self.flags(logfile='/some/path/foo-bar.log')
self.assertEquals(log.get_log_file_path(binary='foo-bar'),
'/some/path/foo-bar.log')
def test_log_path_none(self):
self.assertTrue(log.get_log_file_path(binary='foo-bar') is None)
def test_log_path_logfile_overrides_logdir(self):
self.flags(logdir='/some/other/path',
logfile='/some/path/foo-bar.log')
self.assertEquals(log.get_log_file_path(binary='foo-bar'),
'/some/path/foo-bar.log')
class NovaFormatterTestCase(test.TestCase): class NovaFormatterTestCase(test.TestCase):
def setUp(self): def setUp(self):
super(NovaFormatterTestCase, self).setUp() super(NovaFormatterTestCase, self).setUp()

View File

@@ -32,6 +32,7 @@ from nova.virt import xenapi_conn
from nova.virt.xenapi import fake as xenapi_fake from nova.virt.xenapi import fake as xenapi_fake
from nova.virt.xenapi import volume_utils from nova.virt.xenapi import volume_utils
from nova.virt.xenapi.vmops import SimpleDH from nova.virt.xenapi.vmops import SimpleDH
from nova.virt.xenapi.vmops import VMOps
from nova.tests.db import fakes as db_fakes from nova.tests.db import fakes as db_fakes
from nova.tests.xenapi import stubs from nova.tests.xenapi import stubs
from nova.tests.glance import stubs as glance_stubs from nova.tests.glance import stubs as glance_stubs
@@ -141,6 +142,10 @@ class XenAPIVolumeTestCase(test.TestCase):
self.stubs.UnsetAll() self.stubs.UnsetAll()
def reset_network(*args):
pass
class XenAPIVMTestCase(test.TestCase): class XenAPIVMTestCase(test.TestCase):
""" """
Unit tests for VM operations Unit tests for VM operations
@@ -162,6 +167,7 @@ class XenAPIVMTestCase(test.TestCase):
stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests) stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
stubs.stubout_get_this_vm_uuid(self.stubs) stubs.stubout_get_this_vm_uuid(self.stubs)
stubs.stubout_stream_disk(self.stubs) stubs.stubout_stream_disk(self.stubs)
self.stubs.Set(VMOps, 'reset_network', reset_network)
glance_stubs.stubout_glance_client(self.stubs, glance_stubs.stubout_glance_client(self.stubs,
glance_stubs.FakeGlance) glance_stubs.FakeGlance)
self.conn = xenapi_conn.get_connection(False) self.conn = xenapi_conn.get_connection(False)
@@ -243,7 +249,8 @@ class XenAPIVMTestCase(test.TestCase):
# Check that the VM is running according to XenAPI. # Check that the VM is running according to XenAPI.
self.assertEquals(vm['power_state'], 'Running') self.assertEquals(vm['power_state'], 'Running')
def _test_spawn(self, image_id, kernel_id, ramdisk_id): def _test_spawn(self, image_id, kernel_id, ramdisk_id,
instance_type="m1.large"):
stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests) stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
values = {'name': 1, values = {'name': 1,
'id': 1, 'id': 1,
@@ -252,7 +259,7 @@ class XenAPIVMTestCase(test.TestCase):
'image_id': image_id, 'image_id': image_id,
'kernel_id': kernel_id, 'kernel_id': kernel_id,
'ramdisk_id': ramdisk_id, 'ramdisk_id': ramdisk_id,
'instance_type': 'm1.large', 'instance_type': instance_type,
'mac_address': 'aa:bb:cc:dd:ee:ff', 'mac_address': 'aa:bb:cc:dd:ee:ff',
} }
conn = xenapi_conn.get_connection(False) conn = xenapi_conn.get_connection(False)
@@ -260,6 +267,12 @@ class XenAPIVMTestCase(test.TestCase):
conn.spawn(instance) conn.spawn(instance)
self.check_vm_record(conn) self.check_vm_record(conn)
def test_spawn_not_enough_memory(self):
FLAGS.xenapi_image_service = 'glance'
self.assertRaises(Exception,
self._test_spawn,
1, 2, 3, "m1.xlarge")
def test_spawn_raw_objectstore(self): def test_spawn_raw_objectstore(self):
FLAGS.xenapi_image_service = 'objectstore' FLAGS.xenapi_image_service = 'objectstore'
self._test_spawn(1, None, None) self._test_spawn(1, None, None)

View File

@@ -43,8 +43,6 @@ else:
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
flags.DEFINE_string('logdir', None, 'directory to keep log files in '
'(will be prepended to $logfile)')
class TwistdServerOptions(ServerOptions): class TwistdServerOptions(ServerOptions):

View File

@@ -26,6 +26,8 @@ from nose import config
from nose import result from nose import result
from nose import core from nose import core
from nova import log as logging
class NovaTestResult(result.TextTestResult): class NovaTestResult(result.TextTestResult):
def __init__(self, *args, **kw): def __init__(self, *args, **kw):
@@ -58,6 +60,7 @@ class NovaTestRunner(core.TextTestRunner):
if __name__ == '__main__': if __name__ == '__main__':
logging.basicConfig()
c = config.Config(stream=sys.stdout, c = config.Config(stream=sys.stdout,
env=os.environ, env=os.environ,
verbosity=3, verbosity=3,