From c50d3d633ba871a70846ce715a86758e066e61f3 Mon Sep 17 00:00:00 2001 From: Davanum Srinivas Date: Mon, 11 Nov 2013 20:19:32 -0500 Subject: [PATCH] Adding domain to context and log Add support for upcoming "domain" concept in Keystone V3 API in both logging and context. Closes-Bug: #1248936 Implements: blueprint add-domain-info-to-context Change-Id: Ic2cf3e52cfcc0b8adccdf9c59afaa4014708a303 --- openstack/common/context.py | 21 +++++++++++++++++++-- openstack/common/log.py | 10 ++++++---- tests/unit/test_log.py | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/openstack/common/context.py b/openstack/common/context.py index 2e46d702..182b0443 100644 --- a/openstack/common/context.py +++ b/openstack/common/context.py @@ -36,12 +36,18 @@ class RequestContext(object): accesses the system, as well as additional request information. """ - def __init__(self, auth_token=None, user=None, tenant=None, is_admin=False, + user_idt_format = '{user} {tenant} {domain} {user_domain} {p_domain}' + + def __init__(self, auth_token=None, user=None, tenant=None, domain=None, + user_domain=None, project_domain=None, is_admin=False, read_only=False, show_deleted=False, request_id=None, instance_uuid=None): self.auth_token = auth_token self.user = user self.tenant = tenant + self.domain = domain + self.user_domain = user_domain + self.project_domain = project_domain self.is_admin = is_admin self.read_only = read_only self.show_deleted = show_deleted @@ -51,14 +57,25 @@ class RequestContext(object): self.request_id = request_id def to_dict(self): + user_idt = ( + self.user_idt_format.format(user=self.user or '-', + tenant=self.tenant or '-', + domain=self.domain or '-', + user_domain=self.user_domain or '-', + p_domain=self.project_domain or '-')) + return {'user': self.user, 'tenant': self.tenant, + 'domain': self.domain, + 'user_domain': self.user_domain, + 'project_domain': self.project_domain, 'is_admin': self.is_admin, 'read_only': self.read_only, 'show_deleted': self.show_deleted, 'auth_token': self.auth_token, 'request_id': self.request_id, - 'instance_uuid': self.instance_uuid} + 'instance_uuid': self.instance_uuid, + 'user_identity': user_idt} def get_admin_context(show_deleted=False): diff --git a/openstack/common/log.py b/openstack/common/log.py index 5a4c310d..8fbd8fe2 100644 --- a/openstack/common/log.py +++ b/openstack/common/log.py @@ -130,7 +130,7 @@ generic_log_opts = [ log_opts = [ cfg.StrOpt('logging_context_format_string', default='%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' - '%(name)s [%(request_id)s %(user)s %(tenant)s] ' + '%(name)s [%(request_id)s %(user_identity)s] ' '%(instance)s%(message)s', help='format string to use for log messages with context'), cfg.StrOpt('logging_default_format_string', @@ -332,10 +332,12 @@ class ContextAdapter(BaseLoggerAdapter): elif instance_uuid: instance_extra = (CONF.instance_uuid_format % {'uuid': instance_uuid}) - extra.update({'instance': instance_extra}) + extra['instance'] = instance_extra - extra.update({"project": self.project}) - extra.update({"version": self.version}) + extra.setdefault('user_identity', kwargs.pop('user_identity', None)) + + extra['project'] = self.project + extra['version'] = self.version extra['extra'] = extra.copy() return msg, kwargs diff --git a/tests/unit/test_log.py b/tests/unit/test_log.py index aea4f98b..ec08b94d 100644 --- a/tests/unit/test_log.py +++ b/tests/unit/test_log.py @@ -370,6 +370,43 @@ class FancyRecordTestCase(test.BaseTestCase): (ctxt.request_id, ctxt.instance_uuid))) +class DomainTestCase(test.BaseTestCase): + def setUp(self): + super(DomainTestCase, self).setUp() + self.config = self.useFixture(config.Config()).config + self.config(logging_context_format_string="[%(request_id)s]: " + "%(user_identity)s " + "%(message)s") + self.mylog = log.getLogger() + self.stream = six.StringIO() + handler = logging.StreamHandler(self.stream) + handler.setFormatter(log.ContextFormatter()) + self.mylog.logger.addHandler(handler) + self.mylog.logger.setLevel(logging.DEBUG) + + def _validate_keys(self, ctxt, keyed_log_string): + infoexpected = "%s info\n" % (keyed_log_string) + warnexpected = "%s warn\n" % (keyed_log_string) + + self.mylog.info("info", context=ctxt) + self.assertEqual(infoexpected, self.stream.getvalue()) + + self.mylog.warn("warn", context=ctxt) + self.assertEqual(infoexpected + warnexpected, self.stream.getvalue()) + + def test_domain_in_log_msg(self): + ctxt = _fake_context() + ctxt.domain = 'mydomain' + ctxt.project_domain = 'myprojectdomain' + ctxt.user_domain = 'myuserdomain' + user_identity = ctxt.to_dict()['user_identity'] + self.assertTrue(ctxt.domain in user_identity) + self.assertTrue(ctxt.project_domain in user_identity) + self.assertTrue(ctxt.user_domain in user_identity) + self._validate_keys(ctxt, ('[%s]: %s' % + (ctxt.request_id, user_identity))) + + class SetDefaultsTestCase(test.BaseTestCase): class TestConfigOpts(cfg.ConfigOpts): def __call__(self, args=None):