Merge trunk

This commit is contained in:
Soren Hansen
2010-12-14 18:11:30 +01:00
23 changed files with 461 additions and 205 deletions

View File

@@ -1,3 +1,13 @@
run_tests.err.log run_tests.err.log
.nova-venv .nova-venv
ChangeLog ChangeLog
_trial_temp
keys
networks
nova.sqlite
CA/cacert.pem
CA/index.txt*
CA/openssl.cnf
CA/serial*
CA/newcerts/*.pem
CA/private/cakey.pem

View File

@@ -3,6 +3,7 @@ Anne Gentle <anne@openstack.org>
Anthony Young <sleepsonthefloor@gmail.com> Anthony Young <sleepsonthefloor@gmail.com>
Armando Migliaccio <Armando.Migliaccio@eu.citrix.com> Armando Migliaccio <Armando.Migliaccio@eu.citrix.com>
Chris Behrens <cbehrens@codestud.com> Chris Behrens <cbehrens@codestud.com>
Chmouel Boudjnah <chmouel@chmouel.com>
Dean Troyer <dtroyer@gmail.com> Dean Troyer <dtroyer@gmail.com>
Devin Carlen <devin.carlen@gmail.com> Devin Carlen <devin.carlen@gmail.com>
Eric Day <eday@oddments.org> Eric Day <eday@oddments.org>
@@ -20,8 +21,11 @@ Michael Gundlach <michael.gundlach@rackspace.com>
Monty Taylor <mordred@inaugust.com> Monty Taylor <mordred@inaugust.com>
Paul Voccio <paul@openstack.org> Paul Voccio <paul@openstack.org>
Rick Clark <rick@openstack.org> Rick Clark <rick@openstack.org>
Ryan Lucio <rlucio@internap.com>
Sandy Walsh <sandy.walsh@rackspace.com>
Soren Hansen <soren.hansen@rackspace.com> Soren Hansen <soren.hansen@rackspace.com>
Todd Willey <todd@ansolabs.com> Todd Willey <todd@ansolabs.com>
Trey Morris <trey.morris@rackspace.com>
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>

View File

@@ -38,8 +38,8 @@ from nova import utils
if __name__ == '__main__': if __name__ == '__main__':
utils.default_flagfile()
twistd.serve(__file__) twistd.serve(__file__)
if __name__ == '__builtin__': if __name__ == '__builtin__':
utils.default_flagfile()
application = service.Service.create() # pylint: disable=C0103 application = service.Service.create() # pylint: disable=C0103

View File

@@ -42,10 +42,10 @@ logging.getLogger('boto').setLevel(logging.WARN)
if __name__ == '__main__': if __name__ == '__main__':
utils.default_flagfile()
twistd.serve(__file__) twistd.serve(__file__)
if __name__ == '__builtin__': if __name__ == '__builtin__':
utils.default_flagfile()
logging.warn('Starting instance monitor') logging.warn('Starting instance monitor')
# pylint: disable-msg=C0103 # pylint: disable-msg=C0103
monitor = monitor.InstanceMonitor() monitor = monitor.InstanceMonitor()

View File

@@ -359,9 +359,14 @@ class ProjectCommands(object):
def zipfile(self, project_id, user_id, filename='nova.zip'): def zipfile(self, project_id, user_id, filename='nova.zip'):
"""Exports credentials for project to a zip file """Exports credentials for project to a zip file
arguments: project_id user_id [filename='nova.zip]""" arguments: project_id user_id [filename='nova.zip]"""
zip_file = self.manager.get_credentials(user_id, project_id) try:
with open(filename, 'w') as f: zip_file = self.manager.get_credentials(user_id, project_id)
f.write(zip_file) with open(filename, 'w') as f:
f.write(zip_file)
except db.api.NoMoreNetworks:
print ('No more networks available. If this is a new '
'installation, you need\nto call something like this:\n\n'
' nova-manage network create 10.0.0.0/8 10 64\n\n')
class FloatingIpCommands(object): class FloatingIpCommands(object):

View File

@@ -38,8 +38,8 @@ from nova import utils
if __name__ == '__main__': if __name__ == '__main__':
utils.default_flagfile()
twistd.serve(__file__) twistd.serve(__file__)
if __name__ == '__builtin__': if __name__ == '__builtin__':
utils.default_flagfile()
application = service.Service.create() # pylint: disable-msg=C0103 application = service.Service.create() # pylint: disable-msg=C0103

View File

@@ -42,8 +42,8 @@ FLAGS = flags.FLAGS
if __name__ == '__main__': if __name__ == '__main__':
utils.default_flagfile()
twistd.serve(__file__) twistd.serve(__file__)
if __name__ == '__builtin__': if __name__ == '__builtin__':
utils.default_flagfile()
application = handler.get_application() # pylint: disable-msg=C0103 application = handler.get_application() # pylint: disable-msg=C0103

View File

@@ -38,8 +38,8 @@ from nova import utils
if __name__ == '__main__': if __name__ == '__main__':
utils.default_flagfile()
twistd.serve(__file__) twistd.serve(__file__)
if __name__ == '__builtin__': if __name__ == '__builtin__':
utils.default_flagfile()
application = service.Service.create() application = service.Service.create()

View File

@@ -38,8 +38,8 @@ from nova import utils
if __name__ == '__main__': if __name__ == '__main__':
utils.default_flagfile()
twistd.serve(__file__) twistd.serve(__file__)
if __name__ == '__builtin__': if __name__ == '__builtin__':
utils.default_flagfile()
application = service.Service.create() # pylint: disable-msg=C0103 application = service.Service.create() # pylint: disable-msg=C0103

View File

@@ -40,6 +40,8 @@ flags.DEFINE_string('ldap_user_dn', 'cn=Manager,dc=example,dc=com',
flags.DEFINE_string('ldap_user_unit', 'Users', 'OID for Users') flags.DEFINE_string('ldap_user_unit', 'Users', 'OID for Users')
flags.DEFINE_string('ldap_user_subtree', 'ou=Users,dc=example,dc=com', flags.DEFINE_string('ldap_user_subtree', 'ou=Users,dc=example,dc=com',
'OU for Users') 'OU for Users')
flags.DEFINE_boolean('ldap_user_modify_only', False,
'Modify attributes for users instead of creating/deleting')
flags.DEFINE_string('ldap_project_subtree', 'ou=Groups,dc=example,dc=com', flags.DEFINE_string('ldap_project_subtree', 'ou=Groups,dc=example,dc=com',
'OU for Projects') 'OU for Projects')
flags.DEFINE_string('role_project_subtree', 'ou=Groups,dc=example,dc=com', flags.DEFINE_string('role_project_subtree', 'ou=Groups,dc=example,dc=com',
@@ -89,8 +91,7 @@ class LdapDriver(object):
def get_user(self, uid): def get_user(self, uid):
"""Retrieve user by id""" """Retrieve user by id"""
attr = self.__find_object(self.__uid_to_dn(uid), attr = self.__get_ldap_user(uid)
'(objectclass=novaUser)')
return self.__to_user(attr) return self.__to_user(attr)
def get_user_from_access_key(self, access): def get_user_from_access_key(self, access):
@@ -110,7 +111,12 @@ class LdapDriver(object):
"""Retrieve list of users""" """Retrieve list of users"""
attrs = self.__find_objects(FLAGS.ldap_user_subtree, attrs = self.__find_objects(FLAGS.ldap_user_subtree,
'(objectclass=novaUser)') '(objectclass=novaUser)')
return [self.__to_user(attr) for attr in attrs] users = []
for attr in attrs:
user = self.__to_user(attr)
if user is not None:
users.append(user)
return users
def get_projects(self, uid=None): def get_projects(self, uid=None):
"""Retrieve list of projects""" """Retrieve list of projects"""
@@ -125,21 +131,52 @@ class LdapDriver(object):
"""Create a user""" """Create a user"""
if self.__user_exists(name): if self.__user_exists(name):
raise exception.Duplicate("LDAP user %s already exists" % name) raise exception.Duplicate("LDAP user %s already exists" % name)
attr = [ if FLAGS.ldap_user_modify_only:
('objectclass', ['person', if self.__ldap_user_exists(name):
'organizationalPerson', # Retrieve user by name
'inetOrgPerson', user = self.__get_ldap_user(name)
'novaUser']), # Entry could be malformed, test for missing attrs.
('ou', [FLAGS.ldap_user_unit]), # Malformed entries are useless, replace attributes found.
('uid', [name]), attr = []
('sn', [name]), if 'secretKey' in user.keys():
('cn', [name]), attr.append((self.ldap.MOD_REPLACE, 'secretKey', \
('secretKey', [secret_key]), [secret_key]))
('accessKey', [access_key]), else:
('isAdmin', [str(is_admin).upper()]), attr.append((self.ldap.MOD_ADD, 'secretKey', \
] [secret_key]))
self.conn.add_s(self.__uid_to_dn(name), attr) if 'accessKey' in user.keys():
return self.__to_user(dict(attr)) attr.append((self.ldap.MOD_REPLACE, 'accessKey', \
[access_key]))
else:
attr.append((self.ldap.MOD_ADD, 'accessKey', \
[access_key]))
if 'isAdmin' in user.keys():
attr.append((self.ldap.MOD_REPLACE, 'isAdmin', \
[str(is_admin).upper()]))
else:
attr.append((self.ldap.MOD_ADD, 'isAdmin', \
[str(is_admin).upper()]))
self.conn.modify_s(self.__uid_to_dn(name), attr)
return self.get_user(name)
else:
raise exception.NotFound("LDAP object for %s doesn't exist"
% name)
else:
attr = [
('objectclass', ['person',
'organizationalPerson',
'inetOrgPerson',
'novaUser']),
('ou', [FLAGS.ldap_user_unit]),
('uid', [name]),
('sn', [name]),
('cn', [name]),
('secretKey', [secret_key]),
('accessKey', [access_key]),
('isAdmin', [str(is_admin).upper()]),
]
self.conn.add_s(self.__uid_to_dn(name), attr)
return self.__to_user(dict(attr))
def create_project(self, name, manager_uid, def create_project(self, name, manager_uid,
description=None, member_uids=None): description=None, member_uids=None):
@@ -155,7 +192,7 @@ class LdapDriver(object):
if description is None: if description is None:
description = name description = name
members = [] members = []
if member_uids != None: if member_uids is not None:
for member_uid in member_uids: for member_uid in member_uids:
if not self.__user_exists(member_uid): if not self.__user_exists(member_uid):
raise exception.NotFound("Project can't be created " raise exception.NotFound("Project can't be created "
@@ -256,7 +293,24 @@ class LdapDriver(object):
if not self.__user_exists(uid): if not self.__user_exists(uid):
raise exception.NotFound("User %s doesn't exist" % uid) raise exception.NotFound("User %s doesn't exist" % uid)
self.__remove_from_all(uid) self.__remove_from_all(uid)
self.conn.delete_s(self.__uid_to_dn(uid)) if FLAGS.ldap_user_modify_only:
# Delete attributes
attr = []
# Retrieve user by name
user = self.__get_ldap_user(uid)
if 'secretKey' in user.keys():
attr.append((self.ldap.MOD_DELETE, 'secretKey', \
user['secretKey']))
if 'accessKey' in user.keys():
attr.append((self.ldap.MOD_DELETE, 'accessKey', \
user['accessKey']))
if 'isAdmin' in user.keys():
attr.append((self.ldap.MOD_DELETE, 'isAdmin', \
user['isAdmin']))
self.conn.modify_s(self.__uid_to_dn(uid), attr)
else:
# Delete entry
self.conn.delete_s(self.__uid_to_dn(uid))
def delete_project(self, project_id): def delete_project(self, project_id):
"""Delete a project""" """Delete a project"""
@@ -265,7 +319,7 @@ class LdapDriver(object):
self.__delete_group(project_dn) self.__delete_group(project_dn)
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 project""" """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:
return return
attr = [] attr = []
@@ -279,11 +333,21 @@ class LdapDriver(object):
def __user_exists(self, uid): def __user_exists(self, uid):
"""Check if user exists""" """Check if user exists"""
return self.get_user(uid) != None return self.get_user(uid) is not None
def __ldap_user_exists(self, uid):
"""Check if the user exists in ldap"""
return self.__get_ldap_user(uid) is not None
def __project_exists(self, project_id): def __project_exists(self, project_id):
"""Check if project exists""" """Check if project exists"""
return self.get_project(project_id) != None return self.get_project(project_id) is not None
def __get_ldap_user(self, uid):
"""Retrieve LDAP user entry by id"""
attr = self.__find_object(self.__uid_to_dn(uid),
'(objectclass=novaUser)')
return attr
def __find_object(self, dn, query=None, scope=None): def __find_object(self, dn, query=None, scope=None):
"""Find an object by dn and query""" """Find an object by dn and query"""
@@ -330,12 +394,12 @@ class LdapDriver(object):
def __group_exists(self, dn): def __group_exists(self, dn):
"""Check if group exists""" """Check if group exists"""
return self.__find_object(dn, '(objectclass=groupOfNames)') != None return self.__find_object(dn, '(objectclass=groupOfNames)') is not None
@staticmethod @staticmethod
def __role_to_dn(role, project_id=None): def __role_to_dn(role, project_id=None):
"""Convert role to corresponding dn""" """Convert role to corresponding dn"""
if project_id == None: if project_id is None:
return FLAGS.__getitem__("ldap_%s" % role).value return FLAGS.__getitem__("ldap_%s" % role).value
else: else:
return 'cn=%s,cn=%s,%s' % (role, return 'cn=%s,cn=%s,%s' % (role,
@@ -349,7 +413,7 @@ class LdapDriver(object):
raise exception.Duplicate("Group can't be created because " raise exception.Duplicate("Group can't be created because "
"group %s already exists" % name) "group %s already exists" % name)
members = [] members = []
if member_uids != None: if member_uids is not None:
for member_uid in member_uids: for member_uid in member_uids:
if not self.__user_exists(member_uid): if not self.__user_exists(member_uid):
raise exception.NotFound("Group can't be created " raise exception.NotFound("Group can't be created "
@@ -375,7 +439,7 @@ class LdapDriver(object):
res = self.__find_object(group_dn, res = self.__find_object(group_dn,
'(member=%s)' % self.__uid_to_dn(uid), '(member=%s)' % self.__uid_to_dn(uid),
self.ldap.SCOPE_BASE) self.ldap.SCOPE_BASE)
return res != None return res is not None
def __add_to_group(self, uid, group_dn): def __add_to_group(self, uid, group_dn):
"""Add user to group""" """Add user to group"""
@@ -447,18 +511,22 @@ class LdapDriver(object):
@staticmethod @staticmethod
def __to_user(attr): def __to_user(attr):
"""Convert ldap attributes to User object""" """Convert ldap attributes to User object"""
if attr == None: if attr is None:
return None
if ('accessKey' in attr.keys() and 'secretKey' in attr.keys() \
and 'isAdmin' in attr.keys()):
return {
'id': attr['uid'][0],
'name': attr['cn'][0],
'access': attr['accessKey'][0],
'secret': attr['secretKey'][0],
'admin': (attr['isAdmin'][0] == 'TRUE')}
else:
return None return None
return {
'id': attr['uid'][0],
'name': attr['cn'][0],
'access': attr['accessKey'][0],
'secret': attr['secretKey'][0],
'admin': (attr['isAdmin'][0] == 'TRUE')}
def __to_project(self, attr): def __to_project(self, attr):
"""Convert ldap attributes to Project object""" """Convert ldap attributes to Project object"""
if attr == None: if attr is None:
return None return None
member_dns = attr.get('member', []) member_dns = attr.get('member', [])
return { return {

View File

@@ -624,6 +624,10 @@ class AuthManager(object):
with self.driver() as drv: with self.driver() as drv:
drv.modify_user(uid, access_key, secret_key, admin) drv.modify_user(uid, access_key, secret_key, admin)
@staticmethod
def get_key_pairs(context):
return db.key_pair_get_all_by_user(context.elevated(), context.user_id)
def get_credentials(self, user, project=None): def get_credentials(self, user, project=None):
"""Get credential zip for user in project""" """Get credential zip for user in project"""
if not isinstance(user, User): if not isinstance(user, User):

View File

@@ -0,0 +1,84 @@
#
# Person object for Nova
# inetorgperson with extra attributes
# Author: Vishvananda Ishaya <vishvananda@yahoo.com>
#
#
# using internet experimental oid arc as per BP64 3.1
objectidentifier novaSchema 1.3.6.1.3.1.666.666
objectidentifier novaAttrs novaSchema:3
objectidentifier novaOCs novaSchema:4
attributetype (
novaAttrs:1
NAME 'accessKey'
DESC 'Key for accessing data'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE
)
attributetype (
novaAttrs:2
NAME 'secretKey'
DESC 'Secret key'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE
)
attributetype (
novaAttrs:3
NAME 'keyFingerprint'
DESC 'Fingerprint of private key'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE
)
attributetype (
novaAttrs:4
NAME 'isAdmin'
DESC 'Is user an administrator?'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE
)
attributetype (
novaAttrs:5
NAME 'projectManager'
DESC 'Project Managers of a project'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
)
objectClass (
novaOCs:1
NAME 'novaUser'
DESC 'access and secret keys'
AUXILIARY
MUST ( uid )
MAY ( accessKey $ secretKey $ isAdmin )
)
objectClass (
novaOCs:2
NAME 'novaKeyPair'
DESC 'Key pair for User'
SUP top
STRUCTURAL
MUST ( cn $ sshPublicKey $ keyFingerprint )
)
objectClass (
novaOCs:3
NAME 'novaProject'
DESC 'Container for project'
SUP groupOfNames
STRUCTURAL
MUST ( cn $ projectManager )
)

16
nova/auth/nova_sun.schema Normal file
View File

@@ -0,0 +1,16 @@
#
# Person object for Nova
# inetorgperson with extra attributes
# Author: Vishvananda Ishaya <vishvananda@yahoo.com>
# Modified for strict RFC 4512 compatibility by: Ryan Lane <ryan@ryandlane.com>
#
# using internet experimental oid arc as per BP64 3.1
dn: cn=schema
attributeTypes: ( 1.3.6.1.3.1.666.666.3.1 NAME 'accessKey' DESC 'Key for accessing data' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.3.1.666.666.3.2 NAME 'secretKey' DESC 'Secret key' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.3.1.666.666.3.3 NAME 'keyFingerprint' DESC 'Fingerprint of private key' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE)
attributeTypes: ( 1.3.6.1.3.1.666.666.3.4 NAME 'isAdmin' DESC 'Is user an administrator?' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.3.1.666.666.3.5 NAME 'projectManager' DESC 'Project Managers of a project' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
objectClasses: ( 1.3.6.1.3.1.666.666.4.1 NAME 'novaUser' DESC 'access and secret keys' SUP top AUXILIARY MUST ( uid ) MAY ( accessKey $ secretKey $ isAdmin ) )
objectClasses: ( 1.3.6.1.3.1.666.666.4.2 NAME 'novaKeyPair' DESC 'Key pair for User' SUP top STRUCTURAL MUST ( cn $ sshPublicKey $ keyFingerprint ) )
objectClasses: ( 1.3.6.1.3.1.666.666.4.3 NAME 'novaProject' DESC 'Container for project' SUP groupOfNames STRUCTURAL MUST ( cn $ projectManager ) )

119
nova/auth/opendj.sh Executable file
View File

@@ -0,0 +1,119 @@
#!/usr/bin/env bash
# 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.
# LDAP INSTALL SCRIPT - IS IDEMPOTENT, does not scrub users
apt-get install -y ldap-utils python-ldap openjdk-6-jre
if [ ! -d "/usr/opendj" ]
then
# TODO(rlane): Wikimedia Foundation is the current package maintainer.
# After the package is included in Ubuntu's channel, change this.
wget http://apt.wikimedia.org/wikimedia/pool/main/o/opendj/opendj_2.4.0-7_amd64.deb
dpkg -i opendj_2.4.0-7_amd64.deb
fi
abspath=`dirname "$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")"`
schemapath='/var/opendj/instance/config/schema'
cp $abspath/openssh-lpk_sun.schema $schemapath/97-openssh-lpk_sun.ldif
cp $abspath/nova_sun.schema $schemapath/98-nova_sun.ldif
chown opendj:opendj $schemapath/97-openssh-lpk_sun.ldif
chown opendj:opendj $schemapath/98-nova_sun.ldif
cat >/etc/ldap/ldap.conf <<LDAP_CONF_EOF
# LDAP Client Settings
URI ldap://localhost
BASE dc=example,dc=com
BINDDN cn=Directory Manager
SIZELIMIT 0
TIMELIMIT 0
LDAP_CONF_EOF
cat >/etc/ldap/base.ldif <<BASE_LDIF_EOF
# This is the root of the directory tree
dn: dc=example,dc=com
description: Example.Com, your trusted non-existent corporation.
dc: example
o: Example.Com
objectClass: top
objectClass: dcObject
objectClass: organization
# Subtree for users
dn: ou=Users,dc=example,dc=com
ou: Users
description: Users
objectClass: organizationalUnit
# Subtree for groups
dn: ou=Groups,dc=example,dc=com
ou: Groups
description: Groups
objectClass: organizationalUnit
# Subtree for system accounts
dn: ou=System,dc=example,dc=com
ou: System
description: Special accounts used by software applications.
objectClass: organizationalUnit
# Special Account for Authentication:
dn: uid=authenticate,ou=System,dc=example,dc=com
uid: authenticate
ou: System
description: Special account for authenticating users
userPassword: {MD5}TLnIqASP0CKUR3/LGkEZGg==
objectClass: account
objectClass: simpleSecurityObject
# create the sysadmin entry
dn: cn=developers,ou=Groups,dc=example,dc=com
objectclass: groupOfNames
cn: developers
description: IT admin group
member: uid=admin,ou=Users,dc=example,dc=com
dn: cn=sysadmins,ou=Groups,dc=example,dc=com
objectclass: groupOfNames
cn: sysadmins
description: IT admin group
member: uid=admin,ou=Users,dc=example,dc=com
dn: cn=netadmins,ou=Groups,dc=example,dc=com
objectclass: groupOfNames
cn: netadmins
description: Network admin group
member: uid=admin,ou=Users,dc=example,dc=com
dn: cn=cloudadmins,ou=Groups,dc=example,dc=com
objectclass: groupOfNames
cn: cloudadmins
description: Cloud admin group
member: uid=admin,ou=Users,dc=example,dc=com
dn: cn=itsec,ou=Groups,dc=example,dc=com
objectclass: groupOfNames
cn: itsec
description: IT security users group
member: uid=admin,ou=Users,dc=example,dc=com
BASE_LDIF_EOF
/etc/init.d/opendj stop
su - opendj -c '/usr/opendj/setup -i -b "dc=example,dc=com" -l /etc/ldap/base.ldif -S -w changeme -O -n --noPropertiesFile'
/etc/init.d/opendj start

View File

@@ -0,0 +1,19 @@
#
# LDAP Public Key Patch schema for use with openssh-ldappubkey
# Author: Eric AUGE <eau@phear.org>
#
# Based on the proposal of : Mark Ruijter
#
# octetString SYNTAX
attributetype ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey'
DESC 'MANDATORY: OpenSSH Public key'
EQUALITY octetStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
# printableString SYNTAX yes|no
objectclass ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
DESC 'MANDATORY: OpenSSH LPK objectclass'
MAY ( sshPublicKey $ uid )
)

View File

@@ -0,0 +1,10 @@
#
# LDAP Public Key Patch schema for use with openssh-ldappubkey
# Author: Eric AUGE <eau@phear.org>
#
# Schema for Sun Directory Server.
# Based on the original schema, modified by Stefan Fischer.
#
dn: cn=schema
attributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' DESC 'MANDATORY: OpenSSH Public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
objectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY DESC 'MANDATORY: OpenSSH LPK objectclass' MAY ( sshPublicKey $ uid ) )

View File

@@ -20,115 +20,9 @@
apt-get install -y slapd ldap-utils python-ldap apt-get install -y slapd ldap-utils python-ldap
cat >/etc/ldap/schema/openssh-lpk_openldap.schema <<LPK_SCHEMA_EOF abspath=`dirname "$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")"`
# cp $abspath/openssh-lpk_openldap.schema /etc/ldap/schema/openssh-lpk_openldap.schema
# LDAP Public Key Patch schema for use with openssh-ldappubkey cp $abspath/nova_openldap.schema /etc/ldap/schema/nova_openldap.schema
# Author: Eric AUGE <eau@phear.org>
#
# Based on the proposal of : Mark Ruijter
#
# octetString SYNTAX
attributetype ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey'
DESC 'MANDATORY: OpenSSH Public key'
EQUALITY octetStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
# printableString SYNTAX yes|no
objectclass ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
DESC 'MANDATORY: OpenSSH LPK objectclass'
MAY ( sshPublicKey $ uid )
)
LPK_SCHEMA_EOF
cat >/etc/ldap/schema/nova.schema <<NOVA_SCHEMA_EOF
#
# Person object for Nova
# inetorgperson with extra attributes
# Author: Vishvananda Ishaya <vishvananda@yahoo.com>
#
#
# using internet experimental oid arc as per BP64 3.1
objectidentifier novaSchema 1.3.6.1.3.1.666.666
objectidentifier novaAttrs novaSchema:3
objectidentifier novaOCs novaSchema:4
attributetype (
novaAttrs:1
NAME 'accessKey'
DESC 'Key for accessing data'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE
)
attributetype (
novaAttrs:2
NAME 'secretKey'
DESC 'Secret key'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE
)
attributetype (
novaAttrs:3
NAME 'keyFingerprint'
DESC 'Fingerprint of private key'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE
)
attributetype (
novaAttrs:4
NAME 'isAdmin'
DESC 'Is user an administrator?'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE
)
attributetype (
novaAttrs:5
NAME 'projectManager'
DESC 'Project Managers of a project'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
)
objectClass (
novaOCs:1
NAME 'novaUser'
DESC 'access and secret keys'
AUXILIARY
MUST ( uid )
MAY ( accessKey $ secretKey $ isAdmin )
)
objectClass (
novaOCs:2
NAME 'novaKeyPair'
DESC 'Key pair for User'
SUP top
STRUCTURAL
MUST ( cn $ sshPublicKey $ keyFingerprint )
)
objectClass (
novaOCs:3
NAME 'novaProject'
DESC 'Container for project'
SUP groupOfNames
STRUCTURAL
MUST ( cn $ projectManager )
)
NOVA_SCHEMA_EOF
mv /etc/ldap/slapd.conf /etc/ldap/slapd.conf.orig mv /etc/ldap/slapd.conf /etc/ldap/slapd.conf.orig
cat >/etc/ldap/slapd.conf <<SLAPD_CONF_EOF cat >/etc/ldap/slapd.conf <<SLAPD_CONF_EOF

View File

@@ -223,8 +223,6 @@ DEFINE_string('rabbit_virtual_host', '/', 'rabbit virtual host')
DEFINE_integer('rabbit_retry_interval', 10, 'rabbit connection retry interval') DEFINE_integer('rabbit_retry_interval', 10, 'rabbit connection retry interval')
DEFINE_integer('rabbit_max_retries', 12, 'rabbit connection attempts') DEFINE_integer('rabbit_max_retries', 12, 'rabbit connection attempts')
DEFINE_string('control_exchange', 'nova', 'the main exchange to connect to') DEFINE_string('control_exchange', 'nova', 'the main exchange to connect to')
DEFINE_string('cc_host', '127.0.0.1', 'ip of api server')
DEFINE_integer('cc_port', 8773, 'cloud controller port')
DEFINE_string('ec2_url', 'http://127.0.0.1:8773/services/Cloud', DEFINE_string('ec2_url', 'http://127.0.0.1:8773/services/Cloud',
'Url to ec2 api server') 'Url to ec2 api server')
@@ -264,7 +262,7 @@ DEFINE_string('scheduler_manager', 'nova.scheduler.manager.SchedulerManager',
'Manager for scheduler') 'Manager for scheduler')
# The service to use for image search and retrieval # The service to use for image search and retrieval
DEFINE_string('image_service', 'nova.image.local.LocalImageService', DEFINE_string('image_service', 'nova.image.s3.S3ImageService',
'The service to use for retrieving and searching for images.') 'The service to use for retrieving and searching for images.')
DEFINE_string('host', socket.gethostname(), DEFINE_string('host', socket.gethostname(),

View File

@@ -126,6 +126,19 @@ class CloudTestCase(test.TrialTestCase):
db.instance_destroy(self.context, inst['id']) db.instance_destroy(self.context, inst['id'])
db.floating_ip_destroy(self.context, address) db.floating_ip_destroy(self.context, address)
def test_describe_volumes(self):
"""Makes sure describe_volumes works and filters results."""
vol1 = db.volume_create(self.context, {})
vol2 = db.volume_create(self.context, {})
result = self.cloud.describe_volumes(self.context)
self.assertEqual(len(result['volumeSet']), 2)
result = self.cloud.describe_volumes(self.context,
volume_id=[vol2['ec2_id']])
self.assertEqual(len(result['volumeSet']), 1)
self.assertEqual(result['volumeSet'][0]['volumeId'], vol2['ec2_id'])
db.volume_destroy(self.context, vol1['id'])
db.volume_destroy(self.context, vol2['id'])
def test_console_output(self): def test_console_output(self):
image_id = FLAGS.default_image image_id = FLAGS.default_image
instance_type = FLAGS.default_instance_type instance_type = FLAGS.default_instance_type

View File

@@ -31,6 +31,7 @@ from nova import flags
from nova import test from nova import test
from nova import utils from nova import utils
from nova.auth import manager from nova.auth import manager
from nova.compute import api as compute_api
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
@@ -43,6 +44,7 @@ class ComputeTestCase(test.TrialTestCase):
self.flags(connection_type='fake', self.flags(connection_type='fake',
network_manager='nova.network.manager.FlatManager') network_manager='nova.network.manager.FlatManager')
self.compute = utils.import_object(FLAGS.compute_manager) self.compute = utils.import_object(FLAGS.compute_manager)
self.compute_api = compute_api.ComputeAPI()
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')
@@ -66,26 +68,31 @@ class ComputeTestCase(test.TrialTestCase):
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 test_create_instance_defaults_display_name(self):
"""Verify that an instance cannot be created without a display_name."""
cases = [dict(), dict(display_name=None)]
for instance in cases:
ref = self.compute_api.create_instances(self.context,
FLAGS.default_instance_type, None, **instance)
try:
self.assertNotEqual(ref[0].display_name, None)
finally:
db.instance_destroy(self.context, ref[0]['id'])
def test_create_instance_associates_security_groups(self): def test_create_instance_associates_security_groups(self):
"""Make sure create_instance associates security groups""" """Make sure create_instances associates security groups"""
inst = {}
inst['user_id'] = self.user.id
inst['project_id'] = self.project.id
values = {'name': 'default', values = {'name': 'default',
'description': 'default', 'description': 'default',
'user_id': self.user.id, 'user_id': self.user.id,
'project_id': self.project.id} 'project_id': self.project.id}
group = db.security_group_create(self.context, values) group = db.security_group_create(self.context, values)
ref = self.compute.create_instance(self.context, ref = self.compute_api.create_instances(self.context,
security_groups=[group['id']], FLAGS.default_instance_type, None, security_group=['default'])
**inst)
# reload to get groups
instance_ref = db.instance_get(self.context, ref['id'])
try: try:
self.assertEqual(len(instance_ref['security_groups']), 1) self.assertEqual(len(ref[0]['security_groups']), 1)
finally: finally:
db.security_group_destroy(self.context, group['id']) db.security_group_destroy(self.context, group['id'])
db.instance_destroy(self.context, instance_ref['id']) db.instance_destroy(self.context, ref[0]['id'])
@defer.inlineCallbacks @defer.inlineCallbacks
def test_run_terminate(self): def test_run_terminate(self):

View File

@@ -15,7 +15,6 @@
# under the License. # under the License.
import os import os
import subprocess
from nova import test from nova import test
from nova.utils import parse_mailmap, str_dict_replace from nova.utils import parse_mailmap, str_dict_replace
@@ -24,18 +23,23 @@ from nova.utils import parse_mailmap, str_dict_replace
class ProjectTestCase(test.TrialTestCase): class ProjectTestCase(test.TrialTestCase):
def test_authors_up_to_date(self): def test_authors_up_to_date(self):
if os.path.exists('../.bzr'): if os.path.exists('../.bzr'):
log_cmd = subprocess.Popen(["bzr", "log", "-n0"], contributors = set()
stdout=subprocess.PIPE)
changelog = log_cmd.communicate()[0]
mailmap = parse_mailmap('../.mailmap') mailmap = parse_mailmap('../.mailmap')
contributors = set() import bzrlib.workingtree
for l in changelog.split('\n'): tree = bzrlib.workingtree.WorkingTree.open('..')
l = l.strip() tree.lock_read()
if (l.startswith('author:') or l.startswith('committer:') parents = tree.get_parent_ids()
and not l == 'committer: Tarmac'): g = tree.branch.repository.get_graph()
email = l.split(' ')[-1] for p in parents[1:]:
contributors.add(str_dict_replace(email, mailmap)) rev_ids = [r for r, _ in g.iter_ancestry(parents)
if r != "null:"]
revs = tree.branch.repository.get_revisions(rev_ids)
for r in revs:
for author in r.get_apparent_authors():
email = author.split(' ')[-1]
contributors.add(str_dict_replace(email, mailmap))
authors_file = open('../Authors', 'r').read() authors_file = open('../Authors', 'r').read()

View File

@@ -94,11 +94,12 @@ class QuotaTestCase(test.TrialTestCase):
for i in range(FLAGS.quota_instances): for i in range(FLAGS.quota_instances):
instance_id = self._create_instance() instance_id = self._create_instance()
instance_ids.append(instance_id) instance_ids.append(instance_id)
self.assertRaises(cloud.QuotaError, self.cloud.run_instances, self.assertRaises(quota.QuotaError, self.cloud.run_instances,
self.context, self.context,
min_count=1, min_count=1,
max_count=1, max_count=1,
instance_type='m1.small') instance_type='m1.small',
image_id='fake')
for instance_id in instance_ids: for instance_id in instance_ids:
db.instance_destroy(self.context, instance_id) db.instance_destroy(self.context, instance_id)
@@ -106,11 +107,12 @@ class QuotaTestCase(test.TrialTestCase):
instance_ids = [] instance_ids = []
instance_id = self._create_instance(cores=4) instance_id = self._create_instance(cores=4)
instance_ids.append(instance_id) instance_ids.append(instance_id)
self.assertRaises(cloud.QuotaError, self.cloud.run_instances, self.assertRaises(quota.QuotaError, self.cloud.run_instances,
self.context, self.context,
min_count=1, min_count=1,
max_count=1, max_count=1,
instance_type='m1.small') instance_type='m1.small',
image_id='fake')
for instance_id in instance_ids: for instance_id in instance_ids:
db.instance_destroy(self.context, instance_id) db.instance_destroy(self.context, instance_id)
@@ -119,7 +121,7 @@ class QuotaTestCase(test.TrialTestCase):
for i in range(FLAGS.quota_volumes): for i in range(FLAGS.quota_volumes):
volume_id = self._create_volume() volume_id = self._create_volume()
volume_ids.append(volume_id) volume_ids.append(volume_id)
self.assertRaises(cloud.QuotaError, self.cloud.create_volume, self.assertRaises(quota.QuotaError, self.cloud.create_volume,
self.context, self.context,
size=10) size=10)
for volume_id in volume_ids: for volume_id in volume_ids:
@@ -129,7 +131,7 @@ class QuotaTestCase(test.TrialTestCase):
volume_ids = [] volume_ids = []
volume_id = self._create_volume(size=20) volume_id = self._create_volume(size=20)
volume_ids.append(volume_id) volume_ids.append(volume_id)
self.assertRaises(cloud.QuotaError, self.assertRaises(quota.QuotaError,
self.cloud.create_volume, self.cloud.create_volume,
self.context, self.context,
size=10) size=10)
@@ -146,6 +148,6 @@ class QuotaTestCase(test.TrialTestCase):
# make an rpc.call, the test just finishes with OK. It # make an rpc.call, the test just finishes with OK. It
# appears to be something in the magic inline callbacks # appears to be something in the magic inline callbacks
# that is breaking. # that is breaking.
self.assertRaises(cloud.QuotaError, self.cloud.allocate_address, self.assertRaises(quota.QuotaError, self.cloud.allocate_address,
self.context) self.context)
db.floating_ip_destroy(context.get_admin_context(), address) db.floating_ip_destroy(context.get_admin_context(), address)

View File

@@ -41,15 +41,14 @@ class LibvirtConnTestCase(test.TrialTestCase):
FLAGS.instances_path = '' FLAGS.instances_path = ''
test_ip = '10.11.12.13' test_ip = '10.11.12.13'
test_instance = { test_instance = {'memory_kb': '1024000',
'memory_kb' : '1024000', 'basepath': '/some/path',
'basepath' : '/some/path', 'bridge_name': 'br100',
'bridge_name' : 'br100', 'mac_address': '02:12:34:46:56:67',
'mac_address' : '02:12:34:46:56:67', 'vcpus': 2,
'vcpus' : 2, 'project_id': 'fake',
'project_id' : 'fake', 'bridge': 'br101',
'bridge' : 'br101', 'instance_type': 'm1.small'}
'instance_type' : 'm1.small'}
def test_xml_and_uri_no_ramdisk_no_kernel(self): def test_xml_and_uri_no_ramdisk_no_kernel(self):
instance_data = dict(self.test_instance) instance_data = dict(self.test_instance)
@@ -83,7 +82,6 @@ class LibvirtConnTestCase(test.TrialTestCase):
expect_kernel=True, expect_ramdisk=True, expect_kernel=True, expect_ramdisk=True,
rescue=True) rescue=True)
def do_test_xml_and_uri(self, instance, def do_test_xml_and_uri(self, instance,
expect_ramdisk, expect_kernel, expect_ramdisk, expect_kernel,
rescue=False): rescue=False):
@@ -94,14 +92,14 @@ class LibvirtConnTestCase(test.TrialTestCase):
self.network.set_network_host(context.get_admin_context(), self.network.set_network_host(context.get_admin_context(),
network_ref['id']) network_ref['id'])
fixed_ip = { 'address' : self.test_ip, fixed_ip = {'address': self.test_ip,
'network_id' : network_ref['id'] } 'network_id': network_ref['id']}
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
fixed_ip_ref = db.fixed_ip_create(ctxt, fixed_ip) fixed_ip_ref = db.fixed_ip_create(ctxt, fixed_ip)
db.fixed_ip_update(ctxt, self.test_ip, db.fixed_ip_update(ctxt, self.test_ip,
{ 'allocated': True, {'allocated': True,
'instance_id': instance_ref['id'] }) 'instance_id': instance_ref['id']})
type_uri_map = {'qemu': ('qemu:///system', type_uri_map = {'qemu': ('qemu:///system',
[(lambda t: t.find('.').get('type'), 'qemu'), [(lambda t: t.find('.').get('type'), 'qemu'),
@@ -131,15 +129,15 @@ class LibvirtConnTestCase(test.TrialTestCase):
check_list.append(check) check_list.append(check)
else: else:
if expect_kernel: if expect_kernel:
check = (lambda t: t.find('./os/kernel').text.split('/')[1], check = (lambda t: t.find('./os/kernel').text.split('/'
'kernel') )[1], 'kernel')
else: else:
check = (lambda t: t.find('./os/kernel'), None) check = (lambda t: t.find('./os/kernel'), None)
check_list.append(check) check_list.append(check)
if expect_ramdisk: if expect_ramdisk:
check = (lambda t: t.find('./os/initrd').text.split('/')[1], check = (lambda t: t.find('./os/initrd').text.split('/'
'ramdisk') )[1], 'ramdisk')
else: else:
check = (lambda t: t.find('./os/initrd'), None) check = (lambda t: t.find('./os/initrd'), None)
check_list.append(check) check_list.append(check)
@@ -189,7 +187,8 @@ class LibvirtConnTestCase(test.TrialTestCase):
expected_result, expected_result,
'%s failed common check %d' % (xml, i)) '%s failed common check %d' % (xml, i))
# This test is supposed to make sure we don't override a specifically set uri # This test is supposed to make sure we don't override a specifically
# set uri
# #
# Deliberately not just assigning this string to FLAGS.libvirt_uri and # Deliberately not just assigning this string to FLAGS.libvirt_uri and
# checking against that later on. This way we make sure the # checking against that later on. This way we make sure the