diff options
-rw-r--r-- | nova/api/openstack/compute/contrib/certificates.py | 13 | ||||
-rw-r--r-- | nova/cert/manager.py | 2 | ||||
-rw-r--r-- | nova/cert/rpcapi.py | 71 | ||||
-rw-r--r-- | nova/image/s3.py | 19 | ||||
-rw-r--r-- | nova/tests/cert/__init__.py | 19 | ||||
-rw-r--r-- | nova/tests/cert/test_rpcapi.py | 93 |
6 files changed, 200 insertions, 17 deletions
diff --git a/nova/api/openstack/compute/contrib/certificates.py b/nova/api/openstack/compute/contrib/certificates.py index 601825950..7c33c295e 100644 --- a/nova/api/openstack/compute/contrib/certificates.py +++ b/nova/api/openstack/compute/contrib/certificates.py @@ -19,6 +19,7 @@ import webob.exc from nova.api.openstack import extensions from nova.api.openstack import wsgi from nova.api.openstack import xmlutil +import nova.cert.rpcapi from nova import flags from nova import log as logging from nova import network @@ -64,6 +65,7 @@ class CertificatesController(object): def __init__(self): self.network_api = network.API() + self.cert_rpcapi = nova.cert.rpcapi.CertAPI() super(CertificatesController, self).__init__() @wsgi.serializers(xml=CertificateTemplate) @@ -74,9 +76,8 @@ class CertificatesController(object): if id != 'root': msg = _("Only root certificate can be retrieved.") raise webob.exc.HTTPNotImplemented(explanation=msg) - cert = rpc.call(context, FLAGS.cert_topic, - {"method": "fetch_ca", - "args": {"project_id": context.project_id}}) + cert = self.cert_rpcapi.fetch_ca(context, + project_id=context.project_id) return {'certificate': _translate_certificate_view(cert)} @wsgi.serializers(xml=CertificateTemplate) @@ -84,10 +85,8 @@ class CertificatesController(object): """Return a list of certificates.""" context = req.environ['nova.context'] authorize(context) - pk, cert = rpc.call(context, FLAGS.cert_topic, - {"method": "generate_x509_cert", - "args": {"user_id": context.user_id, - "project_id": context.project_id}}) + pk, cert = self.cert_rpcapi.generate_x509_cert(context, + user_id=context.user_id, project_id=context.project_id) context = req.environ['nova.context'] return {'certificate': _translate_certificate_view(cert, pk)} diff --git a/nova/cert/manager.py b/nova/cert/manager.py index b9f35b72d..840a782c5 100644 --- a/nova/cert/manager.py +++ b/nova/cert/manager.py @@ -36,6 +36,8 @@ FLAGS = flags.FLAGS class CertManager(manager.Manager): + RPC_API_VERSION = '1.0' + def init_host(self): crypto.ensure_ca_filesystem() diff --git a/nova/cert/rpcapi.py b/nova/cert/rpcapi.py new file mode 100644 index 000000000..d062026da --- /dev/null +++ b/nova/cert/rpcapi.py @@ -0,0 +1,71 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012, Red Hat, Inc. +# +# 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. + +""" +Client side of the cert manager RPC API. +""" + +from nova import flags +import nova.rpc.proxy + + +FLAGS = flags.FLAGS + + +class CertAPI(nova.rpc.proxy.RpcProxy): + '''Client side of the cert rpc API. + + API version history: + + 1.0 - Initial version. + ''' + + RPC_API_VERSION = '1.0' + + def __init__(self): + super(CertAPI, self).__init__(topic=FLAGS.cert_topic, + default_version=self.RPC_API_VERSION) + + def revoke_certs_by_user(self, ctxt, user_id): + return self.call(ctxt, self.make_msg('revoke_certs_by_user', + user_id=user_id)) + + def revoke_certs_by_project(self, ctxt, project_id): + return self.call(ctxt, self.make_msg('revoke_certs_by_project', + project_id=project_id)) + + def revoke_certs_by_user_and_project(self, ctxt, user_id, project_id): + return self.call(ctxt, + self.make_msg('revoke_certs_by_user_and_project', + user_id=user_id, project_id=project_id)) + + def generate_x509_cert(self, ctxt, user_id, project_id): + return self.call(ctxt, self.make_msg('generate_x509_cert', + user_id=user_id, + project_id=project_id)) + + def fetch_ca(self, ctxt, project_id): + return self.call(ctxt, self.make_msg('fetch_ca', + project_id=project_id)) + + def fetch_crl(self, ctxt, project_id): + return self.call(ctxt, self.make_msg('fetch_crl', + project_id=project_id)) + + def decrypt_text(self, ctxt, project_id, text): + return self.call(ctxt, self.make_msg('decrypt_text', + project_id=project_id, + text=text)) diff --git a/nova/image/s3.py b/nova/image/s3.py index 31dfa1916..9ed060464 100644 --- a/nova/image/s3.py +++ b/nova/image/s3.py @@ -30,6 +30,7 @@ import eventlet from lxml import etree from nova.api.ec2 import ec2utils +import nova.cert.rpcapi from nova import exception from nova import flags from nova import image @@ -68,6 +69,7 @@ class S3ImageService(object): """Wraps an existing image service to support s3 based register.""" def __init__(self, service=None, *args, **kwargs): + self.cert_rpcapi = nova.cert.rpcapi.CertAPI() self.service = service or image.get_default_image_service() self.service.__init__(*args, **kwargs) @@ -366,23 +368,20 @@ class S3ImageService(object): return image - @staticmethod - def _decrypt_image(context, encrypted_filename, encrypted_key, + def _decrypt_image(self, context, encrypted_filename, encrypted_key, encrypted_iv, decrypted_filename): elevated = context.elevated() try: - key = rpc.call(elevated, FLAGS.cert_topic, - {"method": "decrypt_text", - "args": {"project_id": context.project_id, - "text": base64.b64encode(encrypted_key)}}) + key = self.cert_rpcapi.decrypt_text(elevated, + project_id=context.project_id, + text=base64.b64encode(encrypted_key)) except Exception, exc: msg = _('Failed to decrypt private key: %s') % exc raise exception.NovaException(msg) try: - iv = rpc.call(elevated, FLAGS.cert_topic, - {"method": "decrypt_text", - "args": {"project_id": context.project_id, - "text": base64.b64encode(encrypted_iv)}}) + iv = self.cert_rpcapi.decrypt_text(elevated, + project_id=context.project_id, + text=base64.b64encode(encrypted_iv)) except Exception, exc: raise exception.NovaException(_('Failed to decrypt initialization ' 'vector: %s') % exc) diff --git a/nova/tests/cert/__init__.py b/nova/tests/cert/__init__.py new file mode 100644 index 000000000..7e04e7c73 --- /dev/null +++ b/nova/tests/cert/__init__.py @@ -0,0 +1,19 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# NOTE(vish): this forces the fixtures from tests/__init.py:setup() to work +from nova.tests import * diff --git a/nova/tests/cert/test_rpcapi.py b/nova/tests/cert/test_rpcapi.py new file mode 100644 index 000000000..2e3feeaaf --- /dev/null +++ b/nova/tests/cert/test_rpcapi.py @@ -0,0 +1,93 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012, Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +Unit Tests for nova.cert.rpcapi +""" + +from nova.cert import rpcapi as cert_rpcapi +from nova import context +from nova import flags +from nova import rpc +from nova import test + + +FLAGS = flags.FLAGS + + +class CertRpcAPITestCase(test.TestCase): + + def setUp(self): + super(CertRpcAPITestCase, self).setUp() + + def tearDown(self): + super(CertRpcAPITestCase, self).tearDown() + + def _test_cert_api(self, method, **kwargs): + ctxt = context.RequestContext('fake_user', 'fake_project') + rpcapi = cert_rpcapi.CertAPI() + expected_retval = 'foo' + expected_msg = rpcapi.make_msg(method, **kwargs) + expected_msg['version'] = rpcapi.RPC_API_VERSION + + self.call_ctxt = None + self.call_topic = None + self.call_msg = None + self.call_timeout = None + + def _fake_call(_ctxt, _topic, _msg, _timeout): + self.call_ctxt = _ctxt + self.call_topic = _topic + self.call_msg = _msg + self.call_timeout = _timeout + return expected_retval + + self.stubs.Set(rpc, 'call', _fake_call) + + retval = getattr(rpcapi, method)(ctxt, **kwargs) + + self.assertEqual(retval, expected_retval) + self.assertEqual(self.call_ctxt, ctxt) + self.assertEqual(self.call_topic, FLAGS.cert_topic) + self.assertEqual(self.call_msg, expected_msg) + self.assertEqual(self.call_timeout, None) + + def test_revoke_certs_by_user(self): + self._test_cert_api('revoke_certs_by_user', user_id='fake_user_id') + + def test_revoke_certs_by_project(self): + self._test_cert_api('revoke_certs_by_project', + project_id='fake_project_id') + + def test_revoke_certs_by_user_and_project(self): + self._test_cert_api('revoke_certs_by_user_and_project', + user_id='fake_user_id', + project_id='fake_project_id') + + def test_generate_x509_cert(self): + self._test_cert_api('generate_x509_cert', + user_id='fake_user_id', + project_id='fake_project_id') + + def test_fetch_ca(self): + self._test_cert_api('fetch_ca', project_id='fake_project_id') + + def test_fetch_crl(self): + self._test_cert_api('fetch_crl', project_id='fake_project_id') + + def test_decrypt_text(self): + self._test_cert_api('decrypt_text', + project_id='fake_project_id', text='blah') |