Skip to content

Commit

Permalink
Push up node resource_class/properties/traits to node/lease/offer APIs
Browse files Browse the repository at this point in the history
These attributes are of interest to users, and should be viewable by
users. This PR also renames resource_object 'config' to 'properties',
as that is what that attribute actually represents.
  • Loading branch information
tzumainn committed Mar 20, 2024
1 parent bb1fbad commit 2810ec6
Show file tree
Hide file tree
Showing 18 changed files with 84 additions and 34 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ as specified above. Once you do so, add dummy nodes as follows:
cat <<EOF > /tmp/nodes/1718
{
"project_owner_id": "project id of dummy node owner",
"server_config": {
"properties": {
"new attribute XYZ": "This is just a sample list of free-form attributes used for describing a server.",
"cpu_type": "Intel Xeon",
"cores": 16,
Expand Down
4 changes: 3 additions & 1 deletion esi_leap/api/controllers/v1/lease.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class Lease(base.ESILEAPBase):
resource_type = wsme.wsattr(wtypes.text)
resource_uuid = wsme.wsattr(wtypes.text)
resource_class = wsme.wsattr(wtypes.text)
resource_properties = {wtypes.text: types.jsontype}
resource = wsme.wsattr(wtypes.text, readonly=True)
start_time = wsme.wsattr(datetime.datetime)
fulfill_time = wsme.wsattr(datetime.datetime, readonly=True)
Expand All @@ -62,7 +63,8 @@ def __init__(self, **kwargs):
for field in self.fields:
setattr(self, field, kwargs.get(field, wtypes.Unset))

for attr in ('project', 'owner', 'resource', 'resource_class'):
for attr in ('project', 'owner', 'resource', 'resource_class',
'resource_properties'):
setattr(self, attr, kwargs.get(attr, wtypes.Unset))


Expand Down
8 changes: 7 additions & 1 deletion esi_leap/api/controllers/v1/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class Node(base.ESILEAPBase):
owner = wsme.wsattr(wtypes.text)
maintenance = wsme.wsattr(wtypes.text)
provision_state = wsme.wsattr(wtypes.text)
properties = {wtypes.text: types.jsontype}
resource_class = wsme.wsattr(wtypes.text)
uuid = wsme.wsattr(wtypes.text)
offer_uuid = wsme.wsattr(wtypes.text)
lease_uuid = wsme.wsattr(wtypes.text)
Expand All @@ -46,7 +48,8 @@ class Node(base.ESILEAPBase):
def __init__(self, **kwargs):
self.fields = ('name', 'owner', 'uuid', 'offer_uuid', 'lease_uuid',
'lessee', 'future_offers', 'future_leases',
'provision_state', 'maintenance')
'resource_class', 'provision_state', 'maintenance',
'properties')
for field in self.fields:
setattr(self, field, kwargs.get(field, wtypes.Unset))

Expand Down Expand Up @@ -103,6 +106,9 @@ def get_all(self):

n = Node(name=node.name, uuid=node.uuid,
provision_state=node.provision_state,
resource_class=node.resource_class,
properties=ironic.get_condensed_properties(
node.properties, node.traits),
maintenance=str(node.maintenance),
owner=keystone.get_project_name(node.owner, project_list),
lessee=keystone.get_project_name(node.lessee,
Expand Down
4 changes: 3 additions & 1 deletion esi_leap/api/controllers/v1/offer.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class Offer(base.ESILEAPBase):
resource_uuid = wsme.wsattr(wtypes.text, mandatory=True)
resource = wsme.wsattr(wtypes.text, readonly=True)
resource_class = wsme.wsattr(wtypes.text)
resource_properties = {wtypes.text: types.jsontype}
start_time = wsme.wsattr(datetime.datetime)
end_time = wsme.wsattr(datetime.datetime)
status = wsme.wsattr(wtypes.text, readonly=True)
Expand All @@ -62,7 +63,8 @@ def __init__(self, **kwargs):
setattr(self, field, kwargs.get(field, wtypes.Unset))

for attr in ('availabilities', 'project', 'lessee',
'resource', 'resource_class'):
'resource', 'resource_class',
'resource_properties'):
setattr(self, attr, kwargs.get(attr, wtypes.Unset))


Expand Down
2 changes: 2 additions & 0 deletions esi_leap/api/controllers/v1/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ def offer_get_dict_with_added_info(offer, project_list=None, node_list=None):
o['lessee'] = keystone.get_project_name(offer.lessee_id, project_list)
o['resource'] = resource.get_name(node_list)
o['resource_class'] = resource.get_resource_class(node_list)
o['resource_properties'] = resource.get_properties(node_list)
return o


Expand All @@ -168,6 +169,7 @@ def lease_get_dict_with_added_info(lease, project_list=None, node_list=None):
project_list)
lease_dict['resource'] = resource.get_name(node_list)
lease_dict['resource_class'] = resource.get_resource_class(node_list)
lease_dict['resource_properties'] = resource.get_properties(node_list)
return lease_dict


Expand Down
8 changes: 8 additions & 0 deletions esi_leap/common/ironic.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,11 @@ def get_node(node_uuid, node_list=None):
else:
node = next((n for n in node_list if n.uuid == node_uuid), None)
return node


def get_condensed_properties(properties, traits):
cp = properties.copy()
cp.pop('lease_uuid', None)
cp.pop('capabilities', None)
cp['traits'] = traits
return cp
6 changes: 3 additions & 3 deletions esi_leap/objects/lease.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ def __init__(self, lease, node):
setattr(node, 'node_name', node.get_name())
setattr(node, 'node_provision_state', node.get_node_provision_state())
setattr(node, 'node_power_state', node.get_node_power_state())
node_config = node.get_config().copy()
node_config.pop('lease_uuid', None)
setattr(node, 'node_properties', node_config)
node_properties = node.get_properties().copy()
node_properties.pop('lease_uuid', None)
setattr(node, 'node_properties', node_properties)

self.populate_schema(lease=lease, node=node)

Expand Down
4 changes: 2 additions & 2 deletions esi_leap/resource_objects/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ def get_resource_class(self, resource_list):
"""Return resource's associated class, if any"""

@abc.abstractmethod
def get_config(self):
"""Return resource's associated config, if any"""
def get_properties(self, resource_list):
"""Return resource's associated properties, if any"""

@abc.abstractmethod
def get_owner_project_id(self):
Expand Down
8 changes: 4 additions & 4 deletions esi_leap/resource_objects/dummy_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ def get_resource_class(self, resource_list=None):
err_msg='Error getting resource class',
err_val=error.UNKNOWN['resource_class'])

def get_config(self):
return self._get_node_attr('server_config', {},
err_msg='Error getting resource config',
err_val=error.UNKNOWN['config'])
def get_properties(self, resource_list=None):
return self._get_node_attr('properties', {},
err_msg='Error getting resource properties',
err_val=error.UNKNOWN['properties'])

def get_owner_project_id(self):
return self._get_node_attr('project_owner_id', None,
Expand Down
2 changes: 1 addition & 1 deletion esi_leap/resource_objects/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
'uuid': 'unknown-uuid',
'name': 'unknown-name',
'resource_class': 'unknown-class',
'config': {},
'properties': {},
'owner_project_id': 'unknown-owner',
'lease_uuid': 'unknown-lease',
'lessee_project_id': 'unknown-lessee',
Expand Down
13 changes: 8 additions & 5 deletions esi_leap/resource_objects/ironic_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,14 @@ def get_resource_class(self, resource_list=None):
err_msg='Error getting resource class',
err_val=error.UNKNOWN['resource_class'])

def get_config(self):
config = self._get_node_attr('properties', {},
err_msg='Error getting resource config',
err_val=error.UNKNOWN['config'])
return config
def get_properties(self, resource_list=None):
properties = self._get_node_attr(
'properties', {}, resource_list=resource_list,
err_msg='Error getting resource properties',
err_val=error.UNKNOWN['properties'])
traits = self._get_node_attr(
'traits', [], resource_list=resource_list)
return ironic.get_condensed_properties(properties, traits)

def get_owner_project_id(self):
return self._get_node_attr('owner', '',
Expand Down
2 changes: 1 addition & 1 deletion esi_leap/resource_objects/test_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def get_name(self, resource_list=None):
def get_resource_class(self, resource_list=None):
return 'fake'

def get_config(self):
def get_properties(self, resource_list=None):
return {}

def get_owner_project_id(self):
Expand Down
6 changes: 5 additions & 1 deletion esi_leap/tests/api/controllers/v1/test_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ def __init__(self):
self.name = 'fake-node'
self.owner = 'fake-project-uuid'
self.uuid = 'fake-uuid'
self.properties = {'lease_uuid': 'fake-lease-uuid'}
self.properties = {'lease_uuid': 'fake-lease-uuid', 'cpu': '40'}
self.traits = ['trait1', 'trait2']
self.lessee = 'fake-project-uuid'
self.maintenance = False
self.provision_state = 'active'
self.resource_class = 'baremetal'


class FakeProject(object):
Expand Down Expand Up @@ -61,3 +63,5 @@ def test_get_all(self, mock_gpl, mock_lga, mock_oga, mock_gnl):
self.assertEqual(data['nodes'][0]['owner'], 'fake-project')
self.assertEqual(data['nodes'][0]['lease_uuid'], 'fake-lease-uuid')
self.assertEqual(data['nodes'][0]['lessee'], 'fake-project')
self.assertEqual(data['nodes'][0]['properties'], {
'cpu': '40', 'traits': ['trait1', 'trait2']})
2 changes: 2 additions & 0 deletions esi_leap/tests/api/controllers/v1/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@ def test_offer_get_dict_with_added_info(self,
'resource_type': o.resource_type,
'resource_uuid': o.resource_uuid,
'resource_class': 'fake',
'resource_properties': {},
'resource': 'test-node-1234567890',
'name': o.name,
'project_id': o.project_id,
Expand Down Expand Up @@ -689,6 +690,7 @@ def test_lease_get_dict_with_added_info(self, mock_gro, mock_gpn, mock_gn):
expected_output_dict['project'] = 'project-name'
expected_output_dict['owner'] = 'project-name'
expected_output_dict['resource_class'] = 'fake'
expected_output_dict['resource_properties'] = {}

mock_gro.assert_called_once()
self.assertEqual(2, mock_gpn.call_count)
Expand Down
17 changes: 17 additions & 0 deletions esi_leap/tests/common/test_ironic.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,20 @@ def test_get_node_list_no_match(self, mock_ironic):
node = ironic.get_node('uuid2', node_list)

self.assertEqual(None, node)

def test_get_condensed_properties(self):
properties = {
'lease_uuid': '12345',
'capabilities': 'magic',
'cpu': '40',
'local_gb': '1000'
}
traits = ['trait1', 'trait2']
cp = ironic.get_condensed_properties(
properties, traits)

self.assertEqual(cp, {
'cpu': '40',
'local_gb': '1000',
'traits': ['trait1', 'trait2']
})
10 changes: 5 additions & 5 deletions esi_leap/tests/resource_objects/test_dummy_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class TestDummyNode(base.TestCase):
'resource_class': 'fake',
'power_state': 'off',
'provision_state': 'enroll',
'server_config': {
'properties': {
'new attribute XYZ': 'new attribute XYZ',
'cpu_type': 'Intel Xeon',
'cores': 16,
Expand All @@ -55,7 +55,7 @@ class TestDummyNode(base.TestCase):
test_node_2 = {
'project_owner_id': '123456',
'resource_class': 'fake',
'server_config': {
'properties': {
'new attribute XYZ': 'new attribute XYZ',
'cpu_type': 'Intel Xeon',
'cores': 16,
Expand Down Expand Up @@ -89,11 +89,11 @@ def test_get_resource_class(self):
self.test_node_1['resource_class'])
mock_file_open.assert_called_once()

def test_get_config(self):
def test_get_properties(self):
mock_open = mock.mock_open(read_data=self.fake_read_data_1)
with mock.patch('builtins.open', mock_open) as mock_file_open:
config = self.fake_dummy_node.get_config()
self.assertEqual(config, self.test_node_1['server_config'])
properties = self.fake_dummy_node.get_properties()
self.assertEqual(properties, self.test_node_1['properties'])
mock_file_open.assert_called_once()

def test_get_owner_project_id(self):
Expand Down
16 changes: 10 additions & 6 deletions esi_leap/tests/resource_objects/test_ironic_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ def __init__(self):
self.lessee = 'abcdef'
self.owner = '123456'
self.name = 'fake-node'
self.properties = {'lease_uuid': '001'}
self.properties = {'lease_uuid': '001', 'cpu': '40'}
self.provision_state = 'available'
self.traits = ['trait1', 'trait2']
self.uuid = fake_uuid
self.resource_class = 'baremetal'
self.power_state = 'off'
Expand Down Expand Up @@ -87,15 +88,18 @@ def test_get_resource_class(self, mock_gn):
mock_gn.assert_called_once()

@mock.patch('esi_leap.resource_objects.ironic_node.IronicNode._get_node')
def test_get_config(self, mock_gn):
def test_get_properties(self, mock_gn):
fake_get_node = FakeIronicNode()
mock_gn.return_value = fake_get_node
test_ironic_node = ironic_node.IronicNode(fake_uuid)

config = test_ironic_node.get_config()
expected_config = fake_get_node.properties
self.assertEqual(config, expected_config)
mock_gn.assert_called_once()
properties = test_ironic_node.get_properties()
expected_properties = {
'cpu': '40',
'traits': ['trait1', 'trait2']
}
self.assertEqual(properties, expected_properties)
assert mock_gn.call_count == 2

@mock.patch('esi_leap.resource_objects.ironic_node.IronicNode._get_node')
def test_get_owner_project_id(self, mock_gn):
Expand Down
4 changes: 2 additions & 2 deletions esi_leap/tests/resource_objects/test_test_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ def test_get_name(self):
def test_get_resource_class(self):
self.assertEqual(self.fake_test_node.get_resource_class(), 'fake')

def test_get_config(self):
self.assertEqual(self.fake_test_node.get_config(), {})
def test_get_properties(self):
self.assertEqual(self.fake_test_node.get_properties(), {})

def test_get_owner_project_id(self):
self.assertEqual(self.fake_test_node.get_owner_project_id(), '123456')
Expand Down

0 comments on commit 2810ec6

Please sign in to comment.