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:
parent
2867117b27
commit
eba2f62d6d
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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')
|
||||
|
@ -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')
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user