Optionalize instance_uuid in console_auth_token_get_valid()

The original design of the conversion of consoles to objects and
storing the token authorizations in the database backend proposed
adding the instance UUID to the access URL for consoles and did
additional validation of the instance UUID when getting the token
authorization from the database in the console_auth_token_get_valid()
method.

In testing that design with Tempest jobs, we found that noVNC was not
handling the instance UUID in the access URL as expected and would
not work with existing proxies. So, instead we could change to a design
where we run one websocketproxy per cells v2 cell and avoid adding
instance UUID to access URLs. With that, we need a way to get console
token authorizations from the database without the instance UUID.

Part of blueprint convert-consoles-to-objects

Change-Id: I2bf3b56e6b92c40aaf95fa957de452bd7754d859
This commit is contained in:
melanie witt
2017-07-07 15:55:41 +00:00
parent 295af0f059
commit 9554ced8a3
3 changed files with 50 additions and 10 deletions

View File

@@ -2052,16 +2052,22 @@ def console_auth_token_create(context, values):
return IMPL.console_auth_token_create(context, values)
def console_auth_token_get_valid(context, token_hash, instance_uuid):
def console_auth_token_get_valid(context, token_hash, instance_uuid=None):
"""Get a valid console authorization by token_hash and instance_uuid.
The console authorizations expire at the time specified by their
'expires' column. An expired console auth token will not be returned
to the caller - it is treated as if it does not exist.
If instance_uuid is specified, the token is validated against both
expiry and instance_uuid.
If instance_uuid is not specified, the token is validated against
expiry only.
"""
return IMPL.console_auth_token_get_valid(context,
token_hash,
instance_uuid)
instance_uuid=instance_uuid)
def console_auth_token_destroy_all_by_instance(context, instance_uuid):

View File

@@ -1864,7 +1864,7 @@ def instance_destroy(context, instance_uuid, constraint=None):
filter_by(instance_uuid=instance_uuid).\
soft_delete()
# NOTE(snikitin): We can't use model_query here, because there is no
# column 'deleted' in 'tags' table.
# column 'deleted' in 'tags' or 'console_auth_tokens' tables.
context.session.query(models.Tag).filter_by(
resource_id=instance_uuid).delete()
context.session.query(models.ConsoleAuthToken).filter_by(
@@ -6646,13 +6646,15 @@ def console_auth_token_create(context, values):
@pick_context_manager_reader
def console_auth_token_get_valid(context, token_hash, instance_uuid):
_check_instance_exists_in_project(context, instance_uuid)
return context.session.query(models.ConsoleAuthToken).\
filter_by(token_hash=token_hash).\
filter_by(instance_uuid=instance_uuid).\
filter(models.ConsoleAuthToken.expires > timeutils.utcnow_ts()).\
first()
def console_auth_token_get_valid(context, token_hash, instance_uuid=None):
if instance_uuid is not None:
_check_instance_exists_in_project(context, instance_uuid)
query = context.session.query(models.ConsoleAuthToken).\
filter_by(token_hash=token_hash)
if instance_uuid is not None:
query = query.filter_by(instance_uuid=instance_uuid)
return query.filter(
models.ConsoleAuthToken.expires > timeutils.utcnow_ts()).first()
@pick_context_manager_writer

View File

@@ -10519,6 +10519,7 @@ class ConsoleAuthTokenTestCase(test.TestCase):
db_obj1 = db.console_auth_token_get_valid(self.context, hash1, uuid1)
db_obj2 = db.console_auth_token_get_valid(self.context, hash1, uuid2)
self.assertIsNotNone(db_obj1, "a valid token should be found here")
self.assertEqual(hash1, db_obj1['token_hash'])
self.assertIsNone(db_obj2, "the token uuid should not match")
def test_console_auth_token_destroy_expired_by_host(self):
@@ -10551,6 +10552,37 @@ class ConsoleAuthTokenTestCase(test.TestCase):
self.assertIsNotNone(db_obj2, "a valid token should be found here")
self.assertIsNotNone(db_obj3, "a valid token should be found here")
def test_console_auth_token_get_valid_without_uuid_deleted_instance(self):
uuid1 = uuidsentinel.uuid1
hash1 = utils.get_sha256_str(uuidsentinel.token1)
self._create_instances([uuid1])
self._create(hash1, uuid1, 100)
db_obj1 = db.console_auth_token_get_valid(self.context, hash1)
self.assertIsNotNone(db_obj1, "a valid token should be in database")
db.instance_destroy(self.context, uuid1)
db_obj1 = db.console_auth_token_get_valid(self.context, hash1)
self.assertIsNone(db_obj1, "the token should have been deleted")
def test_console_auth_token_get_valid_without_uuid_by_expiry(self):
uuid1 = uuidsentinel.uuid1
uuid2 = uuidsentinel.uuid2
hash1 = utils.get_sha256_str(uuidsentinel.token1)
hash2 = utils.get_sha256_str(uuidsentinel.token2)
self.addCleanup(timeutils.clear_time_override)
timeutils.set_time_override(timeutils.utcnow())
self._create_instances([uuid1, uuid2])
self._create(hash1, uuid1, 10)
timeutils.advance_time_seconds(100)
self._create(hash2, uuid2, 10)
db_obj1 = db.console_auth_token_get_valid(self.context, hash1)
db_obj2 = db.console_auth_token_get_valid(self.context, hash2)
self.assertIsNone(db_obj1, "the token should have expired")
self.assertIsNotNone(db_obj2, "a valid token should be found here")
class SortMarkerHelper(test.TestCase):
def setUp(self):