Skip to content

Commit

Permalink
Merge pull request #152 from tzumainn/node-properties
Browse files Browse the repository at this point in the history
Push up node resource_class/properties/traits to node/lease/offer APIs
  • Loading branch information
tzumainn committed Mar 21, 2024
2 parents bb1fbad + 2810ec6 commit 326fff7
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 326fff7

Please sign in to comment.