From f52d032be3760aa432b1bf57faedf52c44c18be6 Mon Sep 17 00:00:00 2001
From: Tom Barron <tpb@dyncloud.net>
Date: Wed, 11 May 2016 17:22:30 -0400
Subject: [PATCH] Fix Manila RequestContext.to_dict() AttributeError

During context initialization RequestContext.to_dict() method
may be triggered before all Manila specific keys have been set
in the context, in which case an AttributeError is raised.

Fix to_dict() method to set None values for the Manila specific
keys in the context when these attributes have not yet been
set.

Change-Id: I95381cd0e5478e516c0f6a77f1284c3b5b83d492
Closes-Bug: #1561559
Closes-Bug: #1567043
---
 manila/context.py            | 15 ++++++++-------
 manila/tests/test_context.py | 19 +++++++++++++++++++
 2 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/manila/context.py b/manila/context.py
index e1711c0133..9fec8da85f 100644
--- a/manila/context.py
+++ b/manila/context.py
@@ -108,13 +108,14 @@ class RequestContext(context.RequestContext):
     def to_dict(self):
         values = super(RequestContext, self).to_dict()
         values.update({
-            'user_id': self.user_id,
-            'project_id': self.project_id,
-            'read_deleted': self.read_deleted,
-            'remote_address': self.remote_address,
-            'timestamp': self.timestamp.isoformat(),
-            'quota_class': self.quota_class,
-            'service_catalog': self.service_catalog})
+            'user_id': getattr(self, 'user_id', None),
+            'project_id': getattr(self, 'project_id', None),
+            'read_deleted': getattr(self, 'read_deleted', None),
+            'remote_address': getattr(self, 'remote_address', None),
+            'timestamp': self.timestamp.isoformat() if hasattr(
+                self, 'timestamp') else None,
+            'quota_class': getattr(self, 'quota_class', None),
+            'service_catalog': getattr(self, 'service_catalog', None)})
         return values
 
     @classmethod
diff --git a/manila/tests/test_context.py b/manila/tests/test_context.py
index 87262c95bb..105c6eb725 100644
--- a/manila/tests/test_context.py
+++ b/manila/tests/test_context.py
@@ -84,3 +84,22 @@ class ContextTestCase(test.TestCase):
         # user and tenant kwargs get popped off before we log anything
         self.assertNotIn("'user': 'user'", info['log_msg'])
         self.assertNotIn("'tenant': 'project'", info['log_msg'])
+
+    def test_to_dict_works_w_missing_manila_context_attributes(self):
+        manila_context_attributes = ['user_id', 'project_id', 'read_deleted',
+                                     'remote_address', 'timestamp',
+                                     'quota_class', 'service_catalog']
+        ctxt = context.RequestContext('111', '222', roles=['admin', 'weasel'])
+
+        # Early in context initialization to_dict() can be triggered
+        # before all manila specific context attributes have been set.
+        # Set up this situation here.
+        for attr in manila_context_attributes:
+            delattr(ctxt, attr)
+
+        # We should be able to run to_dict() without getting an
+        # AttributeError exception
+        res = ctxt.to_dict()
+
+        for attr in manila_context_attributes:
+            self.assertIsNone(res[attr])