Browse Source

rework creating admin context - use keystoneauth1 lib

rather than own creator of session and auth_plugin from
keystoneclient library.

Change-Id: Id7f71e08de13e77586832f6d12cba1caff3772fe
tags/3.0.0
Andrey Pavlov 2 years ago
parent
commit
d67adb7223

+ 2
- 4
devstack/plugin.sh View File

@@ -28,6 +28,7 @@ EC2API_CONF_DIR=${EC2API_CONF_DIR:-/etc/ec2api}
28 28
 EC2API_CONF_FILE=${EC2API_CONF_DIR}/ec2api.conf
29 29
 EC2API_DEBUG=${EC2API_DEBUG:-True}
30 30
 EC2API_STATE_PATH=${EC2API_STATE_PATH:=$DATA_DIR/ec2api}
31
+EC2API_AUTH_CACHE_DIR=${EC2API_AUTH_CACHE_DIR:-/var/cache/ec2api}
31 32
 
32 33
 EC2API_SERVICE_PORT=${EC2API_SERVICE_PORT:-8788}
33 34
 EC2API_S3_SERVICE_PORT=${EC2API_S3_SERVICE_PORT:-3334}
@@ -178,12 +179,9 @@ function configure_ec2api {
178 179
     # ec2api Api Configuration
179 180
     #-------------------------
180 181
 
181
-    iniset $EC2API_CONF_FILE DEFAULT admin_tenant_name $SERVICE_TENANT_NAME
182
-    iniset $EC2API_CONF_FILE DEFAULT admin_user $EC2API_ADMIN_USER
183
-    iniset $EC2API_CONF_FILE DEFAULT admin_password $SERVICE_PASSWORD
182
+    configure_auth_token_middleware $EC2API_CONF_FILE $EC2API_ADMIN_USER $EC2API_AUTH_CACHE_DIR
184 183
 
185 184
     iniset $EC2API_CONF_FILE DEFAULT ec2api_workers "$API_WORKERS"
186
-    iniset $EC2API_CONF_FILE DEFAULT keystone_url "$KEYSTONE_SERVICE_URI"
187 185
     iniset $EC2API_CONF_FILE DEFAULT keystone_ec2_tokens_url "$KEYSTONE_SERVICE_URI_V3/ec2tokens"
188 186
     iniset $EC2API_CONF_FILE DEFAULT region_list "$REGION_NAME"
189 187
 

+ 4
- 0
ec2api/api/__init__.py View File

@@ -47,6 +47,10 @@ LOG = logging.getLogger(__name__)
47 47
 ec2_opts = [
48 48
     cfg.StrOpt('keystone_url',
49 49
                default='http://localhost:5000/',
50
+               deprecated_for_removal=True,
51
+               deprecated_reason='code was switched to common section '
52
+                                 '"keystone_authtoken"',
53
+               deprecated_since='Newton',
50 54
                help='URL for getting admin session.'),
51 55
     cfg.StrOpt('keystone_ec2_tokens_url',
52 56
                default='http://localhost:5000/v3/ec2tokens',

+ 52
- 15
ec2api/clients.py View File

@@ -14,6 +14,7 @@
14 14
 
15 15
 from cinderclient import client as cinderclient
16 16
 from glanceclient import client as glanceclient
17
+from keystoneauth1 import loading as ks_loading
17 18
 from keystoneclient.auth.identity.generic import password as keystone_auth
18 19
 from keystoneclient import client as keystoneclient
19 20
 from keystoneclient import session as keystone_session
@@ -31,8 +32,16 @@ logger = logging.getLogger(__name__)
31 32
 ec2_opts = [
32 33
     cfg.BoolOpt('ssl_insecure',
33 34
                 default=False,
35
+                deprecated_for_removal=True,
36
+                deprecated_reason='code was switched to common section '
37
+                                  '"keystone_authtoken"',
38
+                deprecated_since='Newton',
34 39
                 help="Verify HTTPS connections."),
35 40
     cfg.StrOpt('ssl_ca_file',
41
+               deprecated_for_removal=True,
42
+               deprecated_reason='code was switched to common section '
43
+                                 '"keystone_authtoken"',
44
+               deprecated_since='Newton',
36 45
                help="CA certificate file to use to verify "
37 46
                     "connecting clients"),
38 47
     cfg.StrOpt('nova_service_type',
@@ -45,20 +54,34 @@ ec2_opts = [
45 54
                default='volumev2',
46 55
                help='Service type of Volume API, registered in Keystone '
47 56
                     'catalog.'),
48
-    # TODO(andrey-mp): keystone v3 allows to pass domain_name
49
-    # or domain_id to auth. This code should support this feature.
50 57
     cfg.StrOpt('admin_user',
58
+               deprecated_for_removal=True,
59
+               deprecated_reason='code was switched to common section '
60
+                                 '"keystone_authtoken"',
61
+               deprecated_since='Newton',
51 62
                help=_("Admin user to access specific cloud resourses")),
52 63
     cfg.StrOpt('admin_password',
64
+               deprecated_for_removal=True,
65
+               deprecated_reason='code was switched to common section '
66
+                                 '"keystone_authtoken"',
67
+               deprecated_since='Newton',
53 68
                help=_("Admin password"),
54 69
                secret=True),
55 70
     cfg.StrOpt('admin_tenant_name',
71
+               deprecated_for_removal=True,
72
+               deprecated_reason='code was switched to common section '
73
+                                 '"keystone_authtoken"',
74
+               deprecated_since='Newton',
56 75
                help=_("Admin tenant name")),
57 76
 ]
58 77
 
59 78
 CONF = cfg.CONF
60 79
 CONF.register_opts(ec2_opts)
61 80
 
81
+GROUP_AUTHTOKEN = 'keystone_authtoken'
82
+ks_loading.register_session_conf_options(CONF, GROUP_AUTHTOKEN)
83
+ks_loading.register_auth_conf_options(CONF, GROUP_AUTHTOKEN)
84
+
62 85
 
63 86
 # Nova API version with microversions support
64 87
 REQUIRED_NOVA_API_VERSION = '2.1'
@@ -106,8 +129,8 @@ def cinder(context):
106 129
 
107 130
 
108 131
 def keystone(context):
109
-    auth_url = context.session.get_endpoint(service_type='identity')
110
-    return keystoneclient.Client(auth_url=auth_url,
132
+    url = context.session.get_endpoint(service_type='identity')
133
+    return keystoneclient.Client(auth_url=url,
111 134
                                  session=context.session)
112 135
 
113 136
 
@@ -202,27 +225,41 @@ class _rpc_RequestContextSerializer(messaging.NoOpSerializer):
202 225
 _admin_session = None
203 226
 
204 227
 
228
+def get_session_from_deprecated():
229
+    auth = keystone_auth.Password(
230
+        username=CONF.admin_user,
231
+        password=CONF.admin_password,
232
+        project_name=CONF.admin_tenant_name,
233
+        tenant_name=CONF.admin_tenant_name,
234
+        auth_url=CONF.keystone_url,
235
+    )
236
+    params = {'auth': auth}
237
+    update_request_params_with_ssl(params)
238
+    return keystone_session.Session(**params)
239
+
240
+
205 241
 def get_os_admin_session():
206 242
     """Create a context to interact with OpenStack as an administrator."""
207 243
     # NOTE(ft): this is a singletone because keystone's session looks thread
208 244
     # safe for both regular and token renewal requests
209 245
     global _admin_session
210 246
     if not _admin_session:
211
-        auth = keystone_auth.Password(
212
-            username=CONF.admin_user,
213
-            password=CONF.admin_password,
214
-            project_name=CONF.admin_tenant_name,
215
-            tenant_name=CONF.admin_tenant_name,
216
-            auth_url=CONF.keystone_url,
217
-        )
218
-        params = {'auth': auth}
219
-        update_request_params_with_ssl(params)
220
-        _admin_session = keystone_session.Session(**params)
247
+        if not CONF[GROUP_AUTHTOKEN].auth_type:
248
+            _admin_session = get_session_from_deprecated()
249
+        else:
250
+            auth_plugin = ks_loading.load_auth_from_conf_options(
251
+                CONF, GROUP_AUTHTOKEN)
252
+            _admin_session = ks_loading.load_session_from_conf_options(
253
+                CONF, GROUP_AUTHTOKEN, auth=auth_plugin)
221 254
 
222 255
     return _admin_session
223 256
 
224 257
 
225 258
 def update_request_params_with_ssl(params):
226
-    verify = CONF.ssl_ca_file or not CONF.ssl_insecure
259
+    if not CONF[GROUP_AUTHTOKEN].auth_type:
260
+        verify = CONF.ssl_ca_file or not CONF.ssl_insecure
261
+    else:
262
+        verify = (CONF[GROUP_AUTHTOKEN].cafile or
263
+                  not CONF[GROUP_AUTHTOKEN].insecure)
227 264
     if verify is not True:
228 265
         params['verify'] = verify

+ 24
- 0
ec2api/opts.py View File

@@ -11,6 +11,10 @@
11 11
 # limitations under the License.
12 12
 
13 13
 import itertools
14
+import operator
15
+
16
+from keystoneauth1 import loading as ks_loading
17
+from oslo_config import cfg
14 18
 
15 19
 import ec2api.clients
16 20
 import ec2api.db.api
@@ -21,6 +25,9 @@ import ec2api.utils
21 25
 import ec2api.wsgi
22 26
 
23 27
 
28
+CONF = cfg.CONF
29
+
30
+
24 31
 def list_opts():
25 32
     return [
26 33
         ('DEFAULT',
@@ -34,3 +41,20 @@ def list_opts():
34 41
              ec2api.wsgi.wsgi_opts,
35 42
          )),
36 43
     ]
44
+
45
+
46
+GROUP_AUTHTOKEN = 'keystone_authtoken'
47
+
48
+
49
+def list_auth_opts():
50
+    opt_list = ks_loading.register_session_conf_options(CONF, GROUP_AUTHTOKEN)
51
+    opt_list.insert(0, ks_loading.get_auth_common_conf_options()[0])
52
+    # NOTE(mhickey): There are a lot of auth plugins, we just generate
53
+    # the config options for a few common ones
54
+    plugins = ['password', 'v2password', 'v3password']
55
+    for name in plugins:
56
+        for plugin_option in ks_loading.get_auth_plugin_conf_options(name):
57
+            if all(option.name != plugin_option.name for option in opt_list):
58
+                opt_list.append(plugin_option)
59
+    opt_list.sort(key=operator.attrgetter('name'))
60
+    return [(GROUP_AUTHTOKEN, opt_list)]

+ 41
- 4
ec2api/tests/unit/test_context.py View File

@@ -20,22 +20,59 @@ from oslo_config import fixture as config_fixture
20 20
 from oslo_context import context
21 21
 from oslotest import base as test_base
22 22
 
23
+from ec2api import clients
23 24
 from ec2api import context as ec2_context
24 25
 
26
+
25 27
 cfg.CONF.import_opt('keystone_url', 'ec2api.api')
28
+GROUP_AUTHTOKEN = 'keystone_authtoken'
26 29
 
27 30
 
28 31
 class ContextTestCase(test_base.BaseTestCase):
29 32
 
30
-    def setUp(self):
31
-        super(ContextTestCase, self).setUp()
33
+    @mock.patch('keystoneauth1.loading.load_auth_from_conf_options')
34
+    @mock.patch('keystoneauth1.loading.load_session_from_conf_options')
35
+    def test_get_os_admin_context(self, session, auth):
36
+        conf = config_fixture.Config()
37
+        clients._admin_session = None
38
+        conf.config(auth_type='fake', group=GROUP_AUTHTOKEN)
39
+
40
+        imp.reload(ec2_context)
41
+        # NOTE(ft): initialize a regular context to populate oslo_context's
42
+        # local storage to prevent admin context to populate it.
43
+        # Used to implicitly validate overwrite=False argument of the call
44
+        # RequestContext constructor from inside get_os_admin_context
45
+        if not context.get_current():
46
+            ec2_context.RequestContext(None, None)
47
+
48
+        ctx = ec2_context.get_os_admin_context()
49
+        conf = cfg.CONF
50
+        auth.assert_called_once_with(conf, GROUP_AUTHTOKEN)
51
+        auth_plugin = auth.return_value
52
+        session.assert_called_once_with(conf, GROUP_AUTHTOKEN,
53
+                                        auth=auth_plugin)
54
+        self.assertIsNone(ctx.user_id)
55
+        self.assertIsNone(ctx.project_id)
56
+        self.assertIsNone(ctx.auth_token)
57
+        self.assertEqual([], ctx.service_catalog)
58
+        self.assertTrue(ctx.is_os_admin)
59
+        self.assertIsNotNone(ctx.session)
60
+        self.assertIsNotNone(ctx.session.auth)
61
+        self.assertNotEqual(context.get_current(), ctx)
62
+
63
+        session.reset_mock()
64
+        ec2_context.get_os_admin_context()
65
+        self.assertFalse(session.called)
66
+
67
+    @mock.patch('keystoneclient.auth.identity.generic.password.Password')
68
+    def test_get_os_admin_context_deprecated(self, password_plugin):
32 69
         conf = config_fixture.Config()
70
+        clients._admin_session = None
71
+        conf.config(auth_type=None, group=GROUP_AUTHTOKEN)
33 72
         conf.config(admin_user='admin',
34 73
                     admin_password='password',
35 74
                     admin_tenant_name='service')
36 75
 
37
-    @mock.patch('keystoneclient.auth.identity.generic.password.Password')
38
-    def test_get_os_admin_context(self, password_plugin):
39 76
         imp.reload(ec2_context)
40 77
         # NOTE(ft): initialize a regular context to populate oslo_context's
41 78
         # local storage to prevent admin context to populate it.

+ 1
- 0
etc/ec2api/ec2api-config-generator.conf View File

@@ -2,6 +2,7 @@
2 2
 output_file = etc/ec2api/ec2api.conf.sample
3 3
 wrap_width = 79
4 4
 namespace = ec2api
5
+namespace = keystoneauth1
5 6
 namespace = ec2api.api
6 7
 namespace = ec2api.metadata
7 8
 namespace = ec2api.s3

+ 13
- 4
install.sh View File

@@ -4,6 +4,8 @@
4 4
 SERVICE_USERNAME=ec2api
5 5
 SERVICE_PASSWORD=ec2api
6 6
 SERVICE_TENANT=service
7
+# this domain name will be used for project and user
8
+SERVICE_DOMAIN_NAME=Default
7 9
 EC2API_PORT=8788
8 10
 CONNECTION="mysql://ec2api:ec2api@127.0.0.1/ec2api?charset=utf8"
9 11
 LOG_DIR=/var/log/ec2api
@@ -267,15 +269,22 @@ iniset $CONF_FILE DEFAULT api_paste_config $APIPASTE_FILE
267 269
 iniset $CONF_FILE DEFAULT logging_context_format_string "%(asctime)s.%(msecs)03d %(levelname)s %(name)s [%(request_id)s %(user_name)s %(project_name)s] %(instance)s%(message)s"
268 270
 iniset $CONF_FILE DEFAULT log_dir "$LOG_DIR"
269 271
 iniset $CONF_FILE DEFAULT verbose True
270
-iniset $CONF_FILE DEFAULT keystone_url "$OS_AUTH_URL"
271 272
 iniset $CONF_FILE DEFAULT keystone_ec2_tokens_url "$OS_AUTH_URL/v3/ec2tokens"
272 273
 iniset $CONF_FILE database connection "$CONNECTION"
273 274
 iniset $CONF_FILE DEFAULT full_vpc_support "$VPC_SUPPORT"
274 275
 iniset $CONF_FILE DEFAULT external_network "$EXTERNAL_NETWORK"
275 276
 
276
-iniset $CONF_FILE DEFAULT admin_user $SERVICE_USERNAME
277
-iniset $CONF_FILE DEFAULT admin_password $SERVICE_PASSWORD
278
-iniset $CONF_FILE DEFAULT admin_tenant_name $SERVICE_TENANT
277
+GROUP_AUTHTOKEN="keystone_authtoken"
278
+iniset $CONF_FILE $GROUP_AUTHTOKEN signing_dir "$AUTH_CACHE_DIR"
279
+iniset $CONF_FILE $GROUP_AUTHTOKEN auth_uri "$OS_AUTH_URL"
280
+iniset $CONF_FILE $GROUP_AUTHTOKEN auth_url "$OS_AUTH_URL"
281
+iniset $CONF_FILE $GROUP_AUTHTOKEN username $SERVICE_USERNAME
282
+iniset $CONF_FILE $GROUP_AUTHTOKEN password $SERVICE_PASSWORD
283
+iniset $CONF_FILE $GROUP_AUTHTOKEN project_name $SERVICE_TENANT
284
+iniset $CONF_FILE $GROUP_AUTHTOKEN project_domain_name $SERVICE_DOMAIN_NAME
285
+iniset $CONF_FILE $GROUP_AUTHTOKEN user_domain_name $SERVICE_DOMAIN_NAME
286
+iniset $CONF_FILE $GROUP_AUTHTOKEN auth_type password
287
+
279 288
 
280 289
 if [[ -f "$NOVA_CONF" ]]; then
281 290
     # NOTE(ft): use swift instead internal s3 server if enabled

+ 1
- 0
requirements.txt View File

@@ -20,6 +20,7 @@ oslo.utils>=3.16.0 # Apache-2.0
20 20
 Paste # MIT
21 21
 PasteDeploy>=1.5.0 # MIT
22 22
 pbr>=1.6 # Apache-2.0
23
+keystoneauth1>=2.10.0 # Apache-2.0
23 24
 python-cinderclient!=1.7.0,!=1.7.1,>=1.6.0 # Apache-2.0
24 25
 python-glanceclient!=2.4.0,>=2.3.0 # Apache-2.0
25 26
 python-keystoneclient!=2.1.0,>=2.0.0 # Apache-2.0

+ 1
- 0
setup.cfg View File

@@ -28,6 +28,7 @@ setup-hooks =
28 28
 oslo.config.opts =
29 29
     ec2api = ec2api.opts:list_opts
30 30
     ec2api.api = ec2api.api.opts:list_opts
31
+    keystoneauth1 = ec2api.opts:list_auth_opts
31 32
     ec2api.metadata = ec2api.metadata.opts:list_opts
32 33
     ec2api.s3 = ec2api.s3.opts:list_opts
33 34
 

Loading…
Cancel
Save