Add new 'device' DB table to valence

This commit adds new model 'Device' to store the pooled resources
info in the DB.

Partially-Implements: blueprint add-device-orchestration

Change-Id: Ic93caaede23b3924d5897b2cb4583e27a1072938
This commit is contained in:
Anusha Ramineni 2017-08-28 14:50:29 +05:30 committed by akhiljain23
parent 2867117b27
commit eba2f62d6d
6 changed files with 257 additions and 1 deletions

View File

@ -159,3 +159,47 @@ class Connection(object):
:returns: A list of all composed node.
"""
return cls.dbdriver.list_composed_nodes(filters)
@classmethod
def list_devices(cls, filters={}):
"""Get a list of all pooled devices.
:returns: A list of all pooled devices.
"""
return cls.dbdriver.list_devices(filters)
@classmethod
def get_device_by_uuid(cls, device_id):
"""Get specific device by its uuid.
:param device_id: The uuid of device.
:returns: A device with this uuid.
"""
return cls.dbdriver.get_device_by_uuid(device_id)
@classmethod
def delete_device(cls, device_uuid):
"""Delete specific device by its uuid
:param device_uuid: The uuid of device.
"""
cls.dbdriver.delete_device(device_uuid)
@classmethod
def update_device(cls, device_uuid, values):
"""Update properties of a device.
:param device_uuid: The uuid of device.
:param values: The properties to be updated.
:returns: A device after updating.
"""
return cls.dbdriver.update_device(device_uuid, values)
@classmethod
def add_device(cls, values):
"""Add a new device.
:values: The properties for this new device.
:returns: A device created.
"""
return cls.dbdriver.add_device(values)

View File

@ -23,7 +23,8 @@ CONF = valence.conf.CONF
etcd_directories = [
models.PodManager.path,
models.Flavor.path,
models.ComposedNode.path
models.ComposedNode.path,
models.Device.path
]
etcd_client = etcd.Client(CONF.etcd.host, CONF.etcd.port)

View File

@ -44,6 +44,8 @@ def translate_to_models(etcd_resp, model_type):
ret = models.Flavor(**data)
elif model_type == models.ComposedNode.path:
ret = models.ComposedNode(**data)
elif model_type == models.Device.path:
ret = models.Device(**data)
else:
raise exception.ValenceException("Invalid model path '%s' specified.",
model_type)
@ -207,3 +209,50 @@ class EtcdDriver(object):
composed_nodes = [node for node in composed_nodes
if node[key] == value]
return composed_nodes
def list_devices(self, filters={}):
try:
resp = getattr(self.client.read(models.Device.path),
'children', None)
except etcd.EtcdKeyNotFound:
msg = ("Path '/devices' does not exist, the etcd server may "
"not have been initialized appropriately.")
LOG.error(msg)
raise exception.ServiceUnavailable(msg)
devices = []
for dev in resp:
if dev.value is not None:
devices.append(translate_to_models(dev, models.Device.path))
if filters:
for key, value in filters.items():
devices = [dev for dev in devices if dev[key] == value]
return devices
def get_device_by_uuid(self, device_id):
try:
resp = self.client.read(models.Device.etcd_path(device_id))
except etcd.EtcdKeyNotFound:
msg = 'Device {0} not found in database.'.format(device_id)
LOG.exception(msg)
raise exception.NotFound(msg)
return translate_to_models(resp, models.Device.path)
def delete_device(self, device_uuid):
device = self.get_device_by_uuid(device_uuid)
device.delete()
def update_device(self, device_uuid, values):
device = self.get_device_by_uuid(device_uuid)
device.update(values)
return device
def add_device(self, values):
if not values.get('uuid'):
values['uuid'] = uuidutils.generate_uuid()
device = models.Device(**values)
device.save()
return device

View File

@ -215,3 +215,38 @@ class ComposedNode(ModelBaseWithTimeStamp):
'validate': types.Text.validate
}
}
class Device(ModelBaseWithTimeStamp):
path = "/devices"
fields = {
'uuid': {
'validate': types.Text.validate
},
'podm_id': {
'validate': types.Text.validate
},
'node_id': {
'validate': types.Text.validate
},
'type': {
'validate': types.Text.validate
},
'pooled_group_id': {
'validate': types.Text.validate
},
'state': {
'validate': types.Text.validate
},
'properties': {
'validate': types.List(types.Dict).validate
},
'extra': {
'validate': types.List(types.Dict).validate
},
'resource_uri': {
'validate': types.Text.validate
}
}

View File

@ -281,3 +281,107 @@ class TestDBAPI(unittest.TestCase):
mock_etcd_write.assert_called_with(
'/nodes/' + node['uuid'],
json.dumps(result.as_dict()))
@mock.patch('etcd.Client.read')
def test_get_device_by_uuid(self, mock_etcd_read):
device = utils.get_test_device_db_info()
mock_etcd_read.return_value = utils.get_etcd_read_result(
device['uuid'], json.dumps(device))
result = db_api.Connection.get_device_by_uuid(device['uuid'])
self.assertEqual(device, result.as_dict())
mock_etcd_read.assert_called_once_with('/devices/' +
device['uuid'])
@mock.patch('etcd.Client.read')
def test_get_device_not_found(self, mock_etcd_read):
mock_etcd_read.side_effect = etcd.EtcdKeyNotFound
with self.assertRaises(exception.NotFound) as context:
db_api.Connection.get_device_by_uuid('fake_uuid')
self.assertTrue('Device {0} not found in database.'.format(
'fake_uuid') in str(context.exception))
mock_etcd_read.assert_called_with('/devices/' + 'fake_uuid')
@mock.patch('etcd.Client.delete')
@mock.patch('etcd.Client.read')
def test_delete_device(self, mock_etcd_read, mock_etcd_delete):
device = utils.get_test_device_db_info()
mock_etcd_read.return_value = utils.get_etcd_read_result(
device['uuid'], json.dumps(device))
db_api.Connection.delete_device(device['uuid'])
mock_etcd_delete.assert_called_with('/devices/' + device['uuid'])
@freezegun.freeze_time("2017-01-01")
@mock.patch('etcd.Client.write')
@mock.patch('etcd.Client.read')
def test_update_device(self, mock_etcd_read, mock_etcd_write):
device = utils.get_test_device_db_info()
mock_etcd_read.return_value = utils.get_etcd_read_result(
device['uuid'], json.dumps(device))
fake_utcnow = '2017-01-01 00:00:00 UTC'
device['updated_at'] = fake_utcnow
device.update({'resource_uri': 'new_uri'})
result = db_api.Connection.update_device(
device['uuid'], {'resource_uri': 'new_uri'})
self.assertEqual(device, result.as_dict())
mock_etcd_read.assert_called_with('/devices/' + device['uuid'])
mock_etcd_write.assert_called_with('/devices/' + device['uuid'],
json.dumps(result.as_dict()))
@freezegun.freeze_time("2017-01-01")
@mock.patch('etcd.Client.write')
@mock.patch('etcd.Client.read')
def test_add_device(self, mock_etcd_read, mock_etcd_write):
device = utils.get_test_device_db_info()
fake_utcnow = '2017-01-01 00:00:00 UTC'
device['created_at'] = fake_utcnow
device['updated_at'] = fake_utcnow
# Mark this uuid don't exist in etcd db
mock_etcd_read.side_effect = etcd.EtcdKeyNotFound
result = db_api.Connection.add_device(device)
self.assertEqual(device, result.as_dict())
mock_etcd_read.assert_called_once_with('/devices/' +
device['uuid'])
mock_etcd_write.assert_called_once_with('/devices/' +
device['uuid'],
json.dumps(result.as_dict()))
@mock.patch('etcd.Client.read')
def test_list_devices(self, mock_etcd_read):
device = utils.get_test_device_db_info()
device2 = copy.deepcopy(device)
device2['uuid'] = 'ea8e2a25-2901-438d-8157-de7ffd68d051'
device2['podm_id'] = 'mk8elki9-2901-j8j7-8157-de7ffdk8gt7u'
device_list = [device, device2]
mock_etcd_read.return_value = utils.get_etcd_read_list(
'/devices', json.dumps(device), json.dumps(device2))
result = db_api.Connection.list_devices()
result = [dev.as_dict() for dev in result]
self.assertEqual(device_list, result)
mock_etcd_read.assert_called_once_with('/devices')
@mock.patch('etcd.Client.read')
def test_list_devices_with_filters(self, mock_etcd_read):
device = utils.get_test_device_db_info()
device2 = copy.deepcopy(device)
device2['uuid'] = 'ea8e2a25-2901-438d-8157-de7ffd68d051'
device2['podm_id'] = 'mk8elki9-2901-j8j7-8157-de7ffdk8gt7u'
mock_etcd_read.return_value = utils.get_etcd_read_list(
'/devices', json.dumps(device), json.dumps(device2))
result = db_api.Connection.list_devices(
filters={'podm_id': 'mk8elki9-2901-j8j7-8157-de7ffdk8gt7u'})
result = [dev.as_dict() for dev in result]
self.assertEqual([device2], result)
mock_etcd_read.assert_called_once_with('/devices')

View File

@ -113,3 +113,26 @@ def get_test_composed_node_db_info(**kwargs):
'created_at': kwargs.get('created_at', '2016-01-01 00:00:00 UTC'),
'updated_at': kwargs.get('updated_at', '2016-01-01 00:00:00 UTC')
}
def get_test_device_db_info(**kwargs):
return {
'uuid': kwargs.get('uuid', 'ea8e2a25-2901-438d-8157-de7ffd68d051'),
'podm_id': kwargs.get('podm_id',
'fa8e2a25-2901-438d-8157-de7ffd68d052'),
'node_id': kwargs.get('node_id',
'ga8e2a25-2901-438d-8157-de7ffd68d053'),
'type': kwargs.get('type', 'SSD'),
'pooled_group_id': kwargs.get('pooled_group_id', '2001'),
'state': kwargs.get('state', 'allocated'),
'properties': kwargs.get(
'properties',
[{'disk_size': '20'},
{'bandwidth': '100Mbps'}]),
'extra': kwargs.get(
'extra',
[{'mac': '11:11:11:11:11'}]),
'resource_uri': kwargs.get('resource_uri', '/device/11'),
'created_at': kwargs.get('created_at', '2016-01-01 00:00:00 UTC'),
'updated_at': kwargs.get('updated_at', '2016-01-01 00:00:00 UTC')
}