Merge lp:~vishvananda/nova/move-keypairs into lp:~hudson-openstack/nova/trunk

Proposed by Vish Ishaya
Status: Merged
Approved by: Jesse Andrews
Approved revision: 380
Merged at revision: 288
Proposed branch: lp:~vishvananda/nova/move-keypairs
Merge into: lp:~hudson-openstack/nova/trunk
Diff against target: 700 lines (+200/-225)
11 files modified
nova/auth/ldapdriver.py (+0/-60)
nova/auth/manager.py (+6/-101)
nova/cloudpipe/pipelib.py (+2/-2)
nova/crypto.py (+1/-1)
nova/db/api.py (+28/-0)
nova/db/sqlalchemy/api.py (+40/-0)
nova/db/sqlalchemy/models.py (+36/-0)
nova/endpoint/cloud.py (+38/-19)
nova/tests/api_unittest.py (+4/-3)
nova/tests/auth_unittest.py (+0/-31)
nova/tests/cloud_unittest.py (+45/-8)
To merge this branch: bzr merge lp:~vishvananda/nova/move-keypairs
Reviewer Review Type Date Requested Status
Jesse Andrews (community) Approve
Jay Pipes (community) Approve
Review via email: mp+35615@code.launchpad.net

Commit message

Moves keypairs out of ldap and into the common datastore.

Description of the change

Moves keypairs out of ldap and into the common datastore.

To post a comment you must log in.
Revision history for this message
Jay Pipes (jaypipes) wrote :

Rock on. One less thing in LDAP makes Jay a happy boy.

review: Approve
lp:~vishvananda/nova/move-keypairs updated
380. By Vish Ishaya

merged trunk

Revision history for this message
Jesse Andrews (anotherjesse) wrote :

lgtm

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'nova/auth/ldapdriver.py'
2--- nova/auth/ldapdriver.py 2010-09-10 11:52:48 +0000
3+++ nova/auth/ldapdriver.py 2010-09-21 04:21:00 +0000
4@@ -99,13 +99,6 @@
5 dn = FLAGS.ldap_user_subtree
6 return self.__to_user(self.__find_object(dn, query))
7
8- def get_key_pair(self, uid, key_name):
9- """Retrieve key pair by uid and key name"""
10- dn = 'cn=%s,%s' % (key_name,
11- self.__uid_to_dn(uid))
12- attr = self.__find_object(dn, '(objectclass=novaKeyPair)')
13- return self.__to_key_pair(uid, attr)
14-
15 def get_project(self, pid):
16 """Retrieve project by id"""
17 dn = 'cn=%s,%s' % (pid,
18@@ -119,12 +112,6 @@
19 '(objectclass=novaUser)')
20 return [self.__to_user(attr) for attr in attrs]
21
22- def get_key_pairs(self, uid):
23- """Retrieve list of key pairs"""
24- attrs = self.__find_objects(self.__uid_to_dn(uid),
25- '(objectclass=novaKeyPair)')
26- return [self.__to_key_pair(uid, attr) for attr in attrs]
27-
28 def get_projects(self, uid=None):
29 """Retrieve list of projects"""
30 pattern = '(objectclass=novaProject)'
31@@ -154,21 +141,6 @@
32 self.conn.add_s(self.__uid_to_dn(name), attr)
33 return self.__to_user(dict(attr))
34
35- def create_key_pair(self, uid, key_name, public_key, fingerprint):
36- """Create a key pair"""
37- # TODO(vish): possibly refactor this to store keys in their own ou
38- # and put dn reference in the user object
39- attr = [
40- ('objectclass', ['novaKeyPair']),
41- ('cn', [key_name]),
42- ('sshPublicKey', [public_key]),
43- ('keyFingerprint', [fingerprint]),
44- ]
45- self.conn.add_s('cn=%s,%s' % (key_name,
46- self.__uid_to_dn(uid)),
47- attr)
48- return self.__to_key_pair(uid, dict(attr))
49-
50 def create_project(self, name, manager_uid,
51 description=None, member_uids=None):
52 """Create a project"""
53@@ -283,19 +255,10 @@
54 """Delete a user"""
55 if not self.__user_exists(uid):
56 raise exception.NotFound("User %s doesn't exist" % uid)
57- self.__delete_key_pairs(uid)
58 self.__remove_from_all(uid)
59 self.conn.delete_s('uid=%s,%s' % (uid,
60 FLAGS.ldap_user_subtree))
61
62- def delete_key_pair(self, uid, key_name):
63- """Delete a key pair"""
64- if not self.__key_pair_exists(uid, key_name):
65- raise exception.NotFound("Key Pair %s doesn't exist for user %s" %
66- (key_name, uid))
67- self.conn.delete_s('cn=%s,uid=%s,%s' % (key_name, uid,
68- FLAGS.ldap_user_subtree))
69-
70 def delete_project(self, project_id):
71 """Delete a project"""
72 project_dn = 'cn=%s,%s' % (project_id, FLAGS.ldap_project_subtree)
73@@ -306,10 +269,6 @@
74 """Check if user exists"""
75 return self.get_user(uid) != None
76
77- def __key_pair_exists(self, uid, key_name):
78- """Check if key pair exists"""
79- return self.get_key_pair(uid, key_name) != None
80-
81 def __project_exists(self, project_id):
82 """Check if project exists"""
83 return self.get_project(project_id) != None
84@@ -359,13 +318,6 @@
85 """Check if group exists"""
86 return self.__find_object(dn, '(objectclass=groupOfNames)') != None
87
88- def __delete_key_pairs(self, uid):
89- """Delete all key pairs for user"""
90- keys = self.get_key_pairs(uid)
91- if keys != None:
92- for key in keys:
93- self.delete_key_pair(uid, key['name'])
94-
95 @staticmethod
96 def __role_to_dn(role, project_id=None):
97 """Convert role to corresponding dn"""
98@@ -490,18 +442,6 @@
99 'secret': attr['secretKey'][0],
100 'admin': (attr['isAdmin'][0] == 'TRUE')}
101
102- @staticmethod
103- def __to_key_pair(owner, attr):
104- """Convert ldap attributes to KeyPair object"""
105- if attr == None:
106- return None
107- return {
108- 'id': attr['cn'][0],
109- 'name': attr['cn'][0],
110- 'owner_id': owner,
111- 'public_key': attr['sshPublicKey'][0],
112- 'fingerprint': attr['keyFingerprint'][0]}
113-
114 def __to_project(self, attr):
115 """Convert ldap attributes to Project object"""
116 if attr == None:
117
118=== modified file 'nova/auth/manager.py'
119--- nova/auth/manager.py 2010-09-21 03:53:46 +0000
120+++ nova/auth/manager.py 2010-09-21 04:21:00 +0000
121@@ -128,24 +128,6 @@
122 def is_project_manager(self, project):
123 return AuthManager().is_project_manager(self, project)
124
125- def generate_key_pair(self, name):
126- return AuthManager().generate_key_pair(self.id, name)
127-
128- def create_key_pair(self, name, public_key, fingerprint):
129- return AuthManager().create_key_pair(self.id,
130- name,
131- public_key,
132- fingerprint)
133-
134- def get_key_pair(self, name):
135- return AuthManager().get_key_pair(self.id, name)
136-
137- def delete_key_pair(self, name):
138- return AuthManager().delete_key_pair(self.id, name)
139-
140- def get_key_pairs(self):
141- return AuthManager().get_key_pairs(self.id)
142-
143 def __repr__(self):
144 return "User('%s', '%s', '%s', '%s', %s)" % (self.id,
145 self.name,
146@@ -154,29 +136,6 @@
147 self.admin)
148
149
150-class KeyPair(AuthBase):
151- """Represents an ssh key returned from the datastore
152-
153- Even though this object is named KeyPair, only the public key and
154- fingerprint is stored. The user's private key is not saved.
155- """
156-
157- def __init__(self, id, name, owner_id, public_key, fingerprint):
158- AuthBase.__init__(self)
159- self.id = id
160- self.name = name
161- self.owner_id = owner_id
162- self.public_key = public_key
163- self.fingerprint = fingerprint
164-
165- def __repr__(self):
166- return "KeyPair('%s', '%s', '%s', '%s', '%s')" % (self.id,
167- self.name,
168- self.owner_id,
169- self.public_key,
170- self.fingerprint)
171-
172-
173 class Project(AuthBase):
174 """Represents a Project returned from the datastore"""
175
176@@ -663,67 +622,13 @@
177 return User(**user_dict)
178
179 def delete_user(self, user):
180- """Deletes a user"""
181- with self.driver() as drv:
182- drv.delete_user(User.safe_id(user))
183-
184- def generate_key_pair(self, user, key_name):
185- """Generates a key pair for a user
186-
187- Generates a public and private key, stores the public key using the
188- key_name, and returns the private key and fingerprint.
189-
190- @type user: User or uid
191- @param user: User for which to create key pair.
192-
193- @type key_name: str
194- @param key_name: Name to use for the generated KeyPair.
195-
196- @rtype: tuple (private_key, fingerprint)
197- @return: A tuple containing the private_key and fingerprint.
198- """
199- # NOTE(vish): generating key pair is slow so check for legal
200- # creation before creating keypair
201+ """Deletes a user
202+
203+ Additionally deletes all users key_pairs"""
204 uid = User.safe_id(user)
205- with self.driver() as drv:
206- if not drv.get_user(uid):
207- raise exception.NotFound("User %s doesn't exist" % user)
208- if drv.get_key_pair(uid, key_name):
209- raise exception.Duplicate("The keypair %s already exists"
210- % key_name)
211- private_key, public_key, fingerprint = crypto.generate_key_pair()
212- self.create_key_pair(uid, key_name, public_key, fingerprint)
213- return private_key, fingerprint
214-
215- def create_key_pair(self, user, key_name, public_key, fingerprint):
216- """Creates a key pair for user"""
217- with self.driver() as drv:
218- kp_dict = drv.create_key_pair(User.safe_id(user),
219- key_name,
220- public_key,
221- fingerprint)
222- if kp_dict:
223- return KeyPair(**kp_dict)
224-
225- def get_key_pair(self, user, key_name):
226- """Retrieves a key pair for user"""
227- with self.driver() as drv:
228- kp_dict = drv.get_key_pair(User.safe_id(user), key_name)
229- if kp_dict:
230- return KeyPair(**kp_dict)
231-
232- def get_key_pairs(self, user):
233- """Retrieves all key pairs for user"""
234- with self.driver() as drv:
235- kp_list = drv.get_key_pairs(User.safe_id(user))
236- if not kp_list:
237- return []
238- return [KeyPair(**kp_dict) for kp_dict in kp_list]
239-
240- def delete_key_pair(self, user, key_name):
241- """Deletes a key pair for user"""
242- with self.driver() as drv:
243- drv.delete_key_pair(User.safe_id(user), key_name)
244+ db.key_pair_destroy_all_by_user(None, uid)
245+ with self.driver() as drv:
246+ drv.delete_user(uid)
247
248 def get_credentials(self, user, project=None):
249 """Get credential zip for user in project"""
250
251=== modified file 'nova/cloudpipe/pipelib.py'
252--- nova/cloudpipe/pipelib.py 2010-08-16 12:16:21 +0000
253+++ nova/cloudpipe/pipelib.py 2010-09-21 04:21:00 +0000
254@@ -58,7 +58,7 @@
255 z.write(FLAGS.boot_script_template,'autorun.sh')
256 z.close()
257
258- key_name = self.setup_keypair(project.project_manager_id, project_id)
259+ key_name = self.setup_key_pair(project.project_manager_id, project_id)
260 zippy = open(zippath, "r")
261 context = api.APIRequestContext(handler=None, user=project.project_manager, project=project)
262
263@@ -74,7 +74,7 @@
264 security_groups=["vpn-secgroup"])
265 zippy.close()
266
267- def setup_keypair(self, user_id, project_id):
268+ def setup_key_pair(self, user_id, project_id):
269 key_name = '%s%s' % (project_id, FLAGS.vpn_key_suffix)
270 try:
271 private_key, fingerprint = self.manager.generate_key_pair(user_id, key_name)
272
273=== modified file 'nova/crypto.py'
274--- nova/crypto.py 2010-08-16 12:16:21 +0000
275+++ nova/crypto.py 2010-09-21 04:21:00 +0000
276@@ -18,7 +18,7 @@
277
278 """
279 Wrappers around standard crypto, including root and intermediate CAs,
280-SSH keypairs and x509 certificates.
281+SSH key_pairs and x509 certificates.
282 """
283
284 import base64
285
286=== modified file 'nova/db/api.py'
287--- nova/db/api.py 2010-09-12 01:45:35 +0000
288+++ nova/db/api.py 2010-09-21 04:21:00 +0000
289@@ -296,6 +296,34 @@
290 return IMPL.instance_update(context, instance_id, values)
291
292
293+###################
294+
295+
296+def key_pair_create(context, values):
297+ """Create a key_pair from the values dictionary."""
298+ return IMPL.key_pair_create(context, values)
299+
300+
301+def key_pair_destroy(context, user_id, name):
302+ """Destroy the key_pair or raise if it does not exist."""
303+ return IMPL.key_pair_destroy(context, user_id, name)
304+
305+
306+def key_pair_destroy_all_by_user(context, user_id):
307+ """Destroy all key_pairs by user."""
308+ return IMPL.key_pair_destroy_all_by_user(context, user_id)
309+
310+
311+def key_pair_get(context, user_id, name):
312+ """Get a key_pair or raise if it does not exist."""
313+ return IMPL.key_pair_get(context, user_id, name)
314+
315+
316+def key_pair_get_all_by_user(context, user_id):
317+ """Get all key_pairs by user."""
318+ return IMPL.key_pair_get_all_by_user(context, user_id)
319+
320+
321 ####################
322
323
324
325=== modified file 'nova/db/sqlalchemy/api.py'
326--- nova/db/sqlalchemy/api.py 2010-09-12 02:40:38 +0000
327+++ nova/db/sqlalchemy/api.py 2010-09-21 04:21:00 +0000
328@@ -462,6 +462,46 @@
329 ###################
330
331
332+def key_pair_create(_context, values):
333+ key_pair_ref = models.KeyPair()
334+ for (key, value) in values.iteritems():
335+ key_pair_ref[key] = value
336+ key_pair_ref.save()
337+ return key_pair_ref
338+
339+
340+def key_pair_destroy(_context, user_id, name):
341+ session = get_session()
342+ with session.begin():
343+ key_pair_ref = models.KeyPair.find_by_args(user_id,
344+ name,
345+ session=session)
346+ key_pair_ref.delete(session=session)
347+
348+
349+def key_pair_destroy_all_by_user(_context, user_id):
350+ session = get_session()
351+ with session.begin():
352+ # TODO(vish): do we have to use sql here?
353+ session.execute('update key_pairs set deleted=1 where user_id=:id',
354+ {'id': user_id})
355+
356+
357+def key_pair_get(_context, user_id, name):
358+ return models.KeyPair.find_by_args(user_id, name)
359+
360+
361+def key_pair_get_all_by_user(_context, user_id):
362+ session = get_session()
363+ return session.query(models.KeyPair
364+ ).filter_by(user_id=user_id
365+ ).filter_by(deleted=False
366+ ).all()
367+
368+
369+###################
370+
371+
372 def network_count(_context):
373 return models.Network.count()
374
375
376=== modified file 'nova/db/sqlalchemy/models.py'
377--- nova/db/sqlalchemy/models.py 2010-09-12 03:00:56 +0000
378+++ nova/db/sqlalchemy/models.py 2010-09-21 04:21:00 +0000
379@@ -323,6 +323,42 @@
380 uselist=False))
381
382
383+class KeyPair(BASE, NovaBase):
384+ """Represents a public key pair for ssh"""
385+ __tablename__ = 'key_pairs'
386+ id = Column(Integer, primary_key=True)
387+ name = Column(String(255))
388+
389+ user_id = Column(String(255))
390+
391+ fingerprint = Column(String(255))
392+ public_key = Column(Text)
393+
394+ @property
395+ def str_id(self):
396+ return '%s.%s' % (self.user_id, self.name)
397+
398+ @classmethod
399+ def find_by_str(cls, str_id, session=None, deleted=False):
400+ user_id, _sep, name = str_id.partition('.')
401+ return cls.find_by_str(user_id, name, session, deleted)
402+
403+ @classmethod
404+ def find_by_args(cls, user_id, name, session=None, deleted=False):
405+ if not session:
406+ session = get_session()
407+ try:
408+ return session.query(cls
409+ ).filter_by(user_id=user_id
410+ ).filter_by(name=name
411+ ).filter_by(deleted=deleted
412+ ).one()
413+ except exc.NoResultFound:
414+ new_exc = exception.NotFound("No model for user %s, name %s" %
415+ (user_id, name))
416+ raise new_exc.__class__, new_exc, sys.exc_info()[2]
417+
418+
419 class Network(BASE, NovaBase):
420 """Represents a network"""
421 __tablename__ = 'networks'
422
423=== modified file 'nova/endpoint/cloud.py'
424--- nova/endpoint/cloud.py 2010-09-21 04:08:25 +0000
425+++ nova/endpoint/cloud.py 2010-09-21 04:21:00 +0000
426@@ -30,6 +30,7 @@
427
428 from twisted.internet import defer
429
430+from nova import crypto
431 from nova import db
432 from nova import exception
433 from nova import flags
434@@ -37,7 +38,6 @@
435 from nova import rpc
436 from nova import utils
437 from nova.auth import rbac
438-from nova.auth import manager
439 from nova.compute.instance_types import INSTANCE_TYPES
440 from nova.endpoint import images
441
442@@ -51,14 +51,30 @@
443 pass
444
445
446-def _gen_key(user_id, key_name):
447- """ Tuck this into AuthManager """
448+def _gen_key(context, user_id, key_name):
449+ """Generate a key
450+
451+ This is a module level method because it is slow and we need to defer
452+ it into a process pool."""
453 try:
454- mgr = manager.AuthManager()
455- private_key, fingerprint = mgr.generate_key_pair(user_id, key_name)
456+ # NOTE(vish): generating key pair is slow so check for legal
457+ # creation before creating key_pair
458+ try:
459+ db.key_pair_get(context, user_id, key_name)
460+ raise exception.Duplicate("The key_pair %s already exists"
461+ % key_name)
462+ except exception.NotFound:
463+ pass
464+ private_key, public_key, fingerprint = crypto.generate_key_pair()
465+ key = {}
466+ key['user_id'] = user_id
467+ key['name'] = key_name
468+ key['public_key'] = public_key
469+ key['fingerprint'] = fingerprint
470+ db.key_pair_create(context, key)
471+ return {'private_key': private_key, 'fingerprint': fingerprint}
472 except Exception as ex:
473 return {'exception': ex}
474- return {'private_key': private_key, 'fingerprint': fingerprint}
475
476
477 class CloudController(object):
478@@ -193,18 +209,18 @@
479
480 @rbac.allow('all')
481 def describe_key_pairs(self, context, key_name=None, **kwargs):
482- key_pairs = context.user.get_key_pairs()
483+ key_pairs = db.key_pair_get_all_by_user(context, context.user.id)
484 if not key_name is None:
485- key_pairs = [x for x in key_pairs if x.name in key_name]
486+ key_pairs = [x for x in key_pairs if x['name'] in key_name]
487
488 result = []
489 for key_pair in key_pairs:
490 # filter out the vpn keys
491 suffix = FLAGS.vpn_key_suffix
492- if context.user.is_admin() or not key_pair.name.endswith(suffix):
493+ if context.user.is_admin() or not key_pair['name'].endswith(suffix):
494 result.append({
495- 'keyName': key_pair.name,
496- 'keyFingerprint': key_pair.fingerprint,
497+ 'keyName': key_pair['name'],
498+ 'keyFingerprint': key_pair['fingerprint'],
499 })
500
501 return {'keypairsSet': result}
502@@ -220,14 +236,18 @@
503 dcall.callback({'keyName': key_name,
504 'keyFingerprint': kwargs['fingerprint'],
505 'keyMaterial': kwargs['private_key']})
506- pool.apply_async(_gen_key, [context.user.id, key_name],
507+ # TODO(vish): when context is no longer an object, pass it here
508+ pool.apply_async(_gen_key, [None, context.user.id, key_name],
509 callback=_complete)
510 return dcall
511
512 @rbac.allow('all')
513 def delete_key_pair(self, context, key_name, **kwargs):
514- context.user.delete_key_pair(key_name)
515- # aws returns true even if the key doens't exist
516+ try:
517+ db.key_pair_destroy(context, context.user.id, key_name)
518+ except exception.NotFound:
519+ # aws returns true even if the key doesn't exist
520+ pass
521 return True
522
523 @rbac.allow('all')
524@@ -575,11 +595,10 @@
525 launch_time = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
526 key_data = None
527 if kwargs.has_key('key_name'):
528- key_pair = context.user.get_key_pair(kwargs['key_name'])
529- if not key_pair:
530- raise exception.ApiError('Key Pair %s not found' %
531- kwargs['key_name'])
532- key_data = key_pair.public_key
533+ key_pair_ref = db.key_pair_get(context,
534+ context.user.id,
535+ kwargs['key_name'])
536+ key_data = key_pair_ref['public_key']
537
538 # TODO: Get the real security group of launch in here
539 security_group = "default"
540
541=== modified file 'nova/tests/api_unittest.py'
542--- nova/tests/api_unittest.py 2010-08-10 13:55:00 +0000
543+++ nova/tests/api_unittest.py 2010-09-21 04:21:00 +0000
544@@ -41,8 +41,8 @@
545 # it's pretty damn circuitous so apologies if you have to fix
546 # a bug in it
547 # NOTE(jaypipes) The pylint disables here are for R0913 (too many args) which
548-# isn't controllable since boto's HTTPRequest needs that many
549-# args, and for the version-differentiated import of tornado's
550+# isn't controllable since boto's HTTPRequest needs that many
551+# args, and for the version-differentiated import of tornado's
552 # httputil.
553 # NOTE(jaypipes): The disable-msg=E1101 and E1103 below is because pylint is
554 # unable to introspect the deferred's return value properly
555@@ -224,7 +224,8 @@
556 for x in range(random.randint(4, 8)))
557 user = self.manager.create_user('fake', 'fake', 'fake')
558 project = self.manager.create_project('fake', 'fake', 'fake')
559- self.manager.generate_key_pair(user.id, keyname)
560+ # NOTE(vish): create depends on pool, so call helper directly
561+ cloud._gen_key(None, user.id, keyname)
562
563 rv = self.ec2.get_all_key_pairs()
564 results = [k for k in rv if k.name == keyname]
565
566=== modified file 'nova/tests/auth_unittest.py'
567--- nova/tests/auth_unittest.py 2010-09-21 03:53:46 +0000
568+++ nova/tests/auth_unittest.py 2010-09-21 04:21:00 +0000
569@@ -17,8 +17,6 @@
570 # under the License.
571
572 import logging
573-from M2Crypto import BIO
574-from M2Crypto import RSA
575 from M2Crypto import X509
576 import unittest
577
578@@ -65,35 +63,6 @@
579 'export S3_URL="http://127.0.0.1:3333/"\n' +
580 'export EC2_USER_ID="test1"\n')
581
582- def test_006_test_key_storage(self):
583- user = self.manager.get_user('test1')
584- user.create_key_pair('public', 'key', 'fingerprint')
585- key = user.get_key_pair('public')
586- self.assertEqual('key', key.public_key)
587- self.assertEqual('fingerprint', key.fingerprint)
588-
589- def test_007_test_key_generation(self):
590- user = self.manager.get_user('test1')
591- private_key, fingerprint = user.generate_key_pair('public2')
592- key = RSA.load_key_string(private_key, callback=lambda: None)
593- bio = BIO.MemoryBuffer()
594- public_key = user.get_key_pair('public2').public_key
595- key.save_pub_key_bio(bio)
596- converted = crypto.ssl_pub_to_ssh_pub(bio.read())
597- # assert key fields are equal
598- self.assertEqual(public_key.split(" ")[1].strip(),
599- converted.split(" ")[1].strip())
600-
601- def test_008_can_list_key_pairs(self):
602- keys = self.manager.get_user('test1').get_key_pairs()
603- self.assertTrue(filter(lambda k: k.name == 'public', keys))
604- self.assertTrue(filter(lambda k: k.name == 'public2', keys))
605-
606- def test_009_can_delete_key_pair(self):
607- self.manager.get_user('test1').delete_key_pair('public')
608- keys = self.manager.get_user('test1').get_key_pairs()
609- self.assertFalse(filter(lambda k: k.name == 'public', keys))
610-
611 def test_010_can_list_users(self):
612 users = self.manager.get_users()
613 logging.warn(users)
614
615=== modified file 'nova/tests/cloud_unittest.py'
616--- nova/tests/cloud_unittest.py 2010-09-11 07:21:58 +0000
617+++ nova/tests/cloud_unittest.py 2010-09-21 04:21:00 +0000
618@@ -17,13 +17,18 @@
619 # under the License.
620
621 import logging
622+from M2Crypto import BIO
623+from M2Crypto import RSA
624 import StringIO
625 import time
626+
627 from tornado import ioloop
628 from twisted.internet import defer
629 import unittest
630 from xml.etree import ElementTree
631
632+from nova import crypto
633+from nova import db
634 from nova import flags
635 from nova import rpc
636 from nova import test
637@@ -55,16 +60,21 @@
638 proxy=self.compute)
639 self.injected.append(self.compute_consumer.attach_to_tornado(self.ioloop))
640
641- try:
642- manager.AuthManager().create_user('admin', 'admin', 'admin')
643- except: pass
644- admin = manager.AuthManager().get_user('admin')
645- project = manager.AuthManager().create_project('proj', 'admin', 'proj')
646- self.context = api.APIRequestContext(handler=None,project=project,user=admin)
647+ self.manager = manager.AuthManager()
648+ self.user = self.manager.create_user('admin', 'admin', 'admin', True)
649+ self.project = self.manager.create_project('proj', 'admin', 'proj')
650+ self.context = api.APIRequestContext(handler=None,
651+ user=self.user,
652+ project=self.project)
653
654 def tearDown(self):
655- manager.AuthManager().delete_project('proj')
656- manager.AuthManager().delete_user('admin')
657+ self.manager.delete_project(self.project)
658+ self.manager.delete_user(self.user)
659+ super(CloudTestCase, self).setUp()
660+
661+ def _create_key(self, name):
662+ # NOTE(vish): create depends on pool, so just call helper directly
663+ return cloud._gen_key(self.context, self.context.user.id, name)
664
665 def test_console_output(self):
666 if FLAGS.connection_type == 'fake':
667@@ -77,6 +87,33 @@
668 self.assert_(output)
669 rv = yield self.compute.terminate_instance(instance_id)
670
671+
672+ def test_key_generation(self):
673+ result = self._create_key('test')
674+ private_key = result['private_key']
675+ key = RSA.load_key_string(private_key, callback=lambda: None)
676+ bio = BIO.MemoryBuffer()
677+ public_key = db.key_pair_get(self.context,
678+ self.context.user.id,
679+ 'test')['public_key']
680+ key.save_pub_key_bio(bio)
681+ converted = crypto.ssl_pub_to_ssh_pub(bio.read())
682+ # assert key fields are equal
683+ self.assertEqual(public_key.split(" ")[1].strip(),
684+ converted.split(" ")[1].strip())
685+
686+ def test_describe_key_pairs(self):
687+ self._create_key('test1')
688+ self._create_key('test2')
689+ result = self.cloud.describe_key_pairs(self.context)
690+ keys = result["keypairsSet"]
691+ self.assertTrue(filter(lambda k: k['keyName'] == 'test1', keys))
692+ self.assertTrue(filter(lambda k: k['keyName'] == 'test2', keys))
693+
694+ def test_delete_key_pair(self):
695+ self._create_key('test')
696+ self.cloud.delete_key_pair(self.context, 'test')
697+
698 def test_run_instances(self):
699 if FLAGS.connection_type == 'fake':
700 logging.debug("Can't test instances without a real virtual env.")