diff --git a/attachment_swift/README.rst b/attachment_swift/README.rst index a05768d..bcf3c40 100644 --- a/attachment_swift/README.rst +++ b/attachment_swift/README.rst @@ -13,7 +13,8 @@ Activate Swift storage: Configure accesses with environment variables: * ``SWIFT_AUTH_URL`` : URL of the Swift server -* ``SWIFT_TENANT_NAME`` +* ``SWIFT_TENANT_NAME`` : **!** DEPRECATED **!** Use ``SWIFT_PROJECT_NAME`` instead +* ``SWIFT_PROJECT_NAME`` * ``SWIFT_ACCOUNT`` * ``SWIFT_PASSWORD`` * ``SWIFT_REGION_NAME`` : optional region @@ -36,17 +37,19 @@ This addon must be added in the server wide addons with (``--load`` option): Python Dependencies ------------------- -This module needs the python-swiftclient and the python-keystoneclient (For auth v2.0) to work. +This module needs the python-swiftclient and the python-keystoneclient (For auth v3.0) to work. The python-keystoneclient needs the linux package build-essential and python-dev to install properly. The python-swiftclient can be used from the command line, useful to test: - export AUTH_VERSION=2.0 +.. code-block:: sh + + export AUTH_VERSION=3.0 export OS_USERNAME={SWIFT_ACCOUNT} export OS_PASSWORD={SWIFT_PASSWORD} - export OS_TENANT_NAME={SWIFT_TENANT_NAME} - export SWIFT_REGION_NAME={SWIFT_REGION_NAME} - export OS_AUTH_URL=https://auth.cloud.ovh.net/v2.0 + export OS_PROJECT_NAME={SWIFT_PROJECT_NAME} + export OS_REGION_NAME={SWIFT_REGION_NAME} + export OS_AUTH_URL=https://auth.cloud.ovh.net/v3 swift stat More information at diff --git a/attachment_swift/models/ir_attachment.py b/attachment_swift/models/ir_attachment.py index 7616def..e7a3555 100644 --- a/attachment_swift/models/ir_attachment.py +++ b/attachment_swift/models/ir_attachment.py @@ -47,18 +47,18 @@ class SwiftSessionStore(object): def __init__(self): self._sessions = {} - def _get_key(self, auth_url, username, password, tenant_name): - return (auth_url, username, password, tenant_name) + def _get_key(self, auth_url, username, password, project_name): + return (auth_url, username, password, project_name) def get_session(self, auth_url=None, username=None, password=None, - tenant_name=None): - key = self._get_key(auth_url, username, password, tenant_name) + project_name=None): + key = self._get_key(auth_url, username, password, project_name) session = self._sessions.get(key) if not session: - auth = keystoneauth1.identity.v2.Password( + auth = keystoneauth1.identity.v3.Password( username=username, password=password, - tenant_name=tenant_name, + project_name=project_name, auth_url=auth_url, ) session = keystoneauth1.session.Session( @@ -86,12 +86,18 @@ class IrAttachment(models.Model): host = os.environ.get('SWIFT_AUTH_URL') account = os.environ.get('SWIFT_ACCOUNT') password = os.environ.get('SWIFT_PASSWORD') - tenant_name = os.environ.get('SWIFT_TENANT_NAME') + project_name = os.environ.get('SWIFT_PROJECT_NAME') + if not project_name and os.environ.get('SWIFT_TENANT_NAME'): + project_name = os.environ['SWIFT_TENANT_NAME'] + _logger.warning( + "SWIFT_TENANT_NAME is deprecated and " + "must be replaced by SWIFT_PROJECT_NAME" + ) region = os.environ.get('SWIFT_REGION_NAME') os_options = {} if region: os_options['region_name'] = region - if not (host and account and password and tenant_name): + if not (host and account and password and project_name): raise exceptions.UserError(_( "Problem connecting to Swift store, are the env variables " "(SWIFT_AUTH_URL, SWIFT_ACCOUNT, SWIFT_PASSWORD, " @@ -101,7 +107,7 @@ class IrAttachment(models.Model): session = swift_session_store.get_session( username=account, password=password, - tenant_name=tenant_name, + project_name=project_name, auth_url=host, ) conn = swiftclient.client.Connection( diff --git a/attachment_swift/tests/test_mock_swift_api.py b/attachment_swift/tests/test_mock_swift_api.py index 72b088c..11a5421 100644 --- a/attachment_swift/tests/test_mock_swift_api.py +++ b/attachment_swift/tests/test_mock_swift_api.py @@ -1,39 +1,80 @@ -# -*- coding: utf-8 -*- -# Copyright 2017 Camptocamp SA +# Copyright 2017-2019 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) +import base64 +import mock import os from mock import patch -from openerp.addons.base.tests.test_ir_attachment import TestIrAttachment -from ..swift_uri import SwiftUri + +import keystoneauth1 + +from odoo.addons.base.tests.test_ir_attachment import TestIrAttachment +from odoo.addons.attachment_swift.models.ir_attachment import SwiftSessionStore +from odoo.addons.attachment_swift.swift_uri import SwiftUri class TestAttachmentSwift(TestIrAttachment): def setup(self): - super(TestAttachmentSwift, self).setUp() + super().setUp() self.env['ir.config_parameter'].set_param('ir_attachment.location', 'swift') + def test_session_store_get_session(self): + auth_url = 'auth_url' + username = 'username' + password = 'password' + project_name = 'project_name' + store = SwiftSessionStore() + session = store.get_session( + auth_url=auth_url, + username=username, + password=password, + project_name=project_name, + ) + self.assertEqual(session.auth.auth_url, auth_url) + self.assertEqual(session.auth.get_cache_id_elements().get( + 'password_username'), username) + self.assertEqual(session.auth.get_cache_id_elements().get( + 'password_password'), password) + self.assertEqual(session.auth.project_name, project_name) + + # get the same session on a second call + self.assertEqual( + store.get_session( + auth_url=auth_url, + username=username, + password=password, + project_name=project_name, + ), + session + ) + @patch('swiftclient.client') def test_connection(self, mock_swift_client): """ Test the connection to the store""" os.environ['SWIFT_AUTH_URL'] = 'auth_url' os.environ['SWIFT_ACCOUNT'] = 'account' os.environ['SWIFT_PASSWORD'] = 'password' - os.environ['SWIFT_TENANT_NAME'] = 'tenant_name' + os.environ['SWIFT_PROJECT_NAME'] = 'project_name' os.environ['SWIFT_REGION_NAME'] = 'NOWHERE' attachment = self.Attachment attachment._get_swift_connection() mock_swift_client.Connection.assert_called_once_with( - authurl=os.environ.get('SWIFT_AUTH_URL'), - user=os.environ.get('SWIFT_ACCOUNT'), - key=os.environ.get('SWIFT_PASSWORD'), - tenant_name=os.environ.get('SWIFT_TENANT_NAME'), - auth_version='2.0', + session=mock.ANY, os_options={'region_name': os.environ.get('SWIFT_REGION_NAME')}, ) + __, kwargs = mock_swift_client.Connection.call_args + session = kwargs['session'] + self.assertTrue(isinstance(session, keystoneauth1.session.Session)) + self.assertEqual(session.auth.auth_url, os.environ['SWIFT_AUTH_URL']) + self.assertEqual(session.auth.get_cache_id_elements().get( + 'password_username'), os.environ['SWIFT_ACCOUNT']) + self.assertEqual(session.auth.get_cache_id_elements().get( + 'password_password'), os.environ['SWIFT_PASSWORD']) + self.assertEqual(session.auth.project_name, + os.environ['SWIFT_PROJECT_NAME']) def test_store_file_on_swift(self): """ @@ -44,11 +85,11 @@ class TestAttachmentSwift(TestIrAttachment): os.environ['SWIFT_AUTH_URL'] = 'auth_url' os.environ['SWIFT_ACCOUNT'] = 'account' os.environ['SWIFT_PASSWORD'] = 'password' - os.environ['SWIFT_TENANT_NAME'] = 'tenant_name' + os.environ['SWIFT_PROJECT_NAME'] = 'project_name' os.environ['SWIFT_WRITE_CONTAINER'] = 'my_container' container = os.environ.get('SWIFT_WRITE_CONTAINER') attachment = self.Attachment - bin_data = self.blob1_b64.decode('base64') + bin_data = base64.b64decode(self.blob1_b64) with patch('swiftclient.client.Connection') as MockConnection: conn = MockConnection.return_value attachment.create({'name': 'a5', 'datas': self.blob1_b64}) @@ -66,7 +107,7 @@ class TestAttachmentSwift(TestIrAttachment): os.environ['SWIFT_AUTH_URL'] = 'auth_url' os.environ['SWIFT_ACCOUNT'] = 'account' os.environ['SWIFT_PASSWORD'] = 'password' - os.environ['SWIFT_TENANT_NAME'] = 'tenant_name' + os.environ['SWIFT_PROJECT_NAME'] = 'project_name' os.environ['SWIFT_WRITE_CONTAINER'] = 'my_container' attachment = self.Attachment