Allow for composition via flavor
This patch will allow a user to compose a node based on requirements specified in a flavor by including the flavor_id in the composition request. It also changes the contents of the request requirements in the API to be included in a "properties" key. Change-Id: I3052e1d5877e63d4a217ecdcdaee32bdb21cb8ed
This commit is contained in:
parent
6bc8f689b0
commit
9e0627f2e0
@ -1,4 +1,17 @@
|
|||||||
{
|
{
|
||||||
"name": "test_node",
|
"name": "test_node",
|
||||||
"description": "node1",
|
"description": "node1",
|
||||||
|
"properties": {
|
||||||
|
"memory": {
|
||||||
|
"capacity_mib": "8000",
|
||||||
|
"type": "DDR2"
|
||||||
|
},
|
||||||
|
"processor": {
|
||||||
|
"model": "Multi-Core Intel(R) Xeon(R) processor 7xxx Series",
|
||||||
|
"total_cores": "2"
|
||||||
|
},
|
||||||
|
"remote_storage": {
|
||||||
|
"capacity_gib": "100"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,12 @@ node_processor_asset:
|
|||||||
in: body
|
in: body
|
||||||
required: true
|
required: true
|
||||||
type: array
|
type: array
|
||||||
|
node_properties:
|
||||||
|
description: |
|
||||||
|
Dictionary of properties of a composed node.
|
||||||
|
in: body
|
||||||
|
required: false
|
||||||
|
type: dictionary
|
||||||
node_property:
|
node_property:
|
||||||
description: |
|
description: |
|
||||||
Property of composed node including processor , memory , storage info.
|
Property of composed node including processor , memory , storage info.
|
||||||
|
@ -29,6 +29,8 @@ Request
|
|||||||
|
|
||||||
- name: node_request_name
|
- name: node_request_name
|
||||||
- description: node_request_description
|
- description: node_request_description
|
||||||
|
- flavor_id: flavor_uuid
|
||||||
|
- properties: node_properties
|
||||||
|
|
||||||
**Example Node creation request:**
|
**Example Node creation request:**
|
||||||
|
|
||||||
|
@ -24,6 +24,11 @@ def list_flavors():
|
|||||||
return [flavor.as_dict() for flavor in flavor_models]
|
return [flavor.as_dict() for flavor in flavor_models]
|
||||||
|
|
||||||
|
|
||||||
|
def get_flavor(flavorid):
|
||||||
|
flavor = db_api.Connection.get_flavor_by_uuid(flavorid)
|
||||||
|
return flavor.as_dict()
|
||||||
|
|
||||||
|
|
||||||
def create_flavor(values):
|
def create_flavor(values):
|
||||||
flavor = db_api.Connection.create_flavor(values)
|
flavor = db_api.Connection.create_flavor(values)
|
||||||
return flavor.as_dict()
|
return flavor.as_dict()
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
import six
|
import six
|
||||||
|
|
||||||
from valence.common import utils
|
from valence.common import utils
|
||||||
|
from valence.controller import flavors
|
||||||
from valence.db import api as db_api
|
from valence.db import api as db_api
|
||||||
from valence.redfish import redfish
|
from valence.redfish import redfish
|
||||||
|
|
||||||
@ -26,6 +27,32 @@ class Node(object):
|
|||||||
return {key: node_info[key] for key in six.iterkeys(node_info)
|
return {key: node_info[key] for key in six.iterkeys(node_info)
|
||||||
if key in ["uuid", "name", "links"]}
|
if key in ["uuid", "name", "links"]}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _create_compose_request(name, description, requirements):
|
||||||
|
request = {}
|
||||||
|
|
||||||
|
request["Name"] = name
|
||||||
|
request["Description"] = description
|
||||||
|
|
||||||
|
memory = {}
|
||||||
|
if "memory" in requirements:
|
||||||
|
if "capacity_mib" in requirements["memory"]:
|
||||||
|
memory["CapacityMiB"] = requirements["memory"]["capacity_mib"]
|
||||||
|
if "type" in requirements["memory"]:
|
||||||
|
memory["DimmDeviceType"] = requirements["memory"]["type"]
|
||||||
|
request["Memory"] = [memory]
|
||||||
|
|
||||||
|
processor = {}
|
||||||
|
if "processor" in requirements:
|
||||||
|
if "model" in requirements["processor"]:
|
||||||
|
processor["Model"] = requirements["processor"]["model"]
|
||||||
|
if "total_cores" in requirements["processor"]:
|
||||||
|
processor["TotalCores"] = (
|
||||||
|
requirements["processor"]["total_cores"])
|
||||||
|
request["Processors"] = [processor]
|
||||||
|
|
||||||
|
return request
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def compose_node(cls, request_body):
|
def compose_node(cls, request_body):
|
||||||
"""Compose new node
|
"""Compose new node
|
||||||
@ -34,8 +61,26 @@ class Node(object):
|
|||||||
return: brief info of this new composed node
|
return: brief info of this new composed node
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if "flavor_id" in request_body:
|
||||||
|
flavor = flavors.get_flavor(request_body["flavor_id"])
|
||||||
|
requirements = flavor["properties"]
|
||||||
|
elif "properties" in request_body:
|
||||||
|
requirements = request_body["properties"]
|
||||||
|
else:
|
||||||
|
requirements = {
|
||||||
|
"memory": {},
|
||||||
|
"processor": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
name = request_body["name"]
|
||||||
|
description = request_body["description"]
|
||||||
|
|
||||||
|
compose_request = cls._create_compose_request(name,
|
||||||
|
description,
|
||||||
|
requirements)
|
||||||
|
|
||||||
# Call redfish to compose new node
|
# Call redfish to compose new node
|
||||||
composed_node = redfish.compose_node(request_body)
|
composed_node = redfish.compose_node(compose_request)
|
||||||
|
|
||||||
composed_node["uuid"] = utils.generate_uuid()
|
composed_node["uuid"] = utils.generate_uuid()
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ def get_test_composed_node(**kwargs):
|
|||||||
'vlans': [{'status': 'Enabled',
|
'vlans': [{'status': 'Enabled',
|
||||||
'vlanid': 99}]}],
|
'vlanid': 99}]}],
|
||||||
'processor': [{'instruction_set': None,
|
'processor': [{'instruction_set': None,
|
||||||
'model': None,
|
'model': 'None',
|
||||||
'speed_mhz': 3700,
|
'speed_mhz': 3700,
|
||||||
'total_core': 0}]})
|
'total_core': 2}]})
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import mock
|
|||||||
from valence.controller import nodes
|
from valence.controller import nodes
|
||||||
from valence.tests.unit.controller import fakes
|
from valence.tests.unit.controller import fakes
|
||||||
from valence.tests.unit.db import utils as test_utils
|
from valence.tests.unit.db import utils as test_utils
|
||||||
|
from valence.tests.unit.fakes import flavor_fakes
|
||||||
|
|
||||||
|
|
||||||
class TestAPINodes(unittest.TestCase):
|
class TestAPINodes(unittest.TestCase):
|
||||||
@ -39,6 +40,37 @@ class TestAPINodes(unittest.TestCase):
|
|||||||
self.assertEqual(expected,
|
self.assertEqual(expected,
|
||||||
nodes.Node._show_node_brief_info(node_info))
|
nodes.Node._show_node_brief_info(node_info))
|
||||||
|
|
||||||
|
def test_create_compose_request(self):
|
||||||
|
name = "test_request"
|
||||||
|
description = "request for testing purposes"
|
||||||
|
requirements = {
|
||||||
|
"memory": {
|
||||||
|
"capacity_mib": "4000",
|
||||||
|
"type": "DDR3"
|
||||||
|
},
|
||||||
|
"processor": {
|
||||||
|
"model": "Intel",
|
||||||
|
"total_cores": "4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"Name": "test_request",
|
||||||
|
"Description": "request for testing purposes",
|
||||||
|
"Memory": [{
|
||||||
|
"CapacityMiB": "4000",
|
||||||
|
"DimmDeviceType": "DDR3"
|
||||||
|
}],
|
||||||
|
"Processors": [{
|
||||||
|
"Model": "Intel",
|
||||||
|
"TotalCores": "4"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
result = nodes.Node._create_compose_request(name,
|
||||||
|
description,
|
||||||
|
requirements)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
@mock.patch("valence.db.api.Connection.create_composed_node")
|
@mock.patch("valence.db.api.Connection.create_composed_node")
|
||||||
@mock.patch("valence.common.utils.generate_uuid")
|
@mock.patch("valence.common.utils.generate_uuid")
|
||||||
@mock.patch("valence.redfish.redfish.compose_node")
|
@mock.patch("valence.redfish.redfish.compose_node")
|
||||||
@ -55,12 +87,46 @@ class TestAPINodes(unittest.TestCase):
|
|||||||
uuid = 'ea8e2a25-2901-438d-8157-de7ffd68d051'
|
uuid = 'ea8e2a25-2901-438d-8157-de7ffd68d051'
|
||||||
mock_generate_uuid.return_value = uuid
|
mock_generate_uuid.return_value = uuid
|
||||||
|
|
||||||
result = nodes.Node.compose_node({"name": "test"})
|
result = nodes.Node.compose_node(
|
||||||
|
{"name": node_hw["name"],
|
||||||
|
"description": node_hw["description"]})
|
||||||
expected = nodes.Node._show_node_brief_info(node_hw)
|
expected = nodes.Node._show_node_brief_info(node_hw)
|
||||||
|
|
||||||
self.assertEqual(expected, result)
|
self.assertEqual(expected, result)
|
||||||
mock_db_create_composed_node.assert_called_once_with(node_db)
|
mock_db_create_composed_node.assert_called_once_with(node_db)
|
||||||
|
|
||||||
|
@mock.patch("valence.db.api.Connection.create_composed_node")
|
||||||
|
@mock.patch("valence.common.utils.generate_uuid")
|
||||||
|
@mock.patch("valence.redfish.redfish.compose_node")
|
||||||
|
@mock.patch("valence.controller.flavors.get_flavor")
|
||||||
|
def test_compose_node_with_flavor(self, mock_get_flavor,
|
||||||
|
mock_redfish_compose_node,
|
||||||
|
mock_generate_uuid,
|
||||||
|
mock_db_create_composed_node):
|
||||||
|
"""Test node composition using a flavor for requirements"""
|
||||||
|
node_hw = fakes.get_test_composed_node()
|
||||||
|
node_db = {"uuid": node_hw["uuid"],
|
||||||
|
"index": node_hw["index"],
|
||||||
|
"name": node_hw["name"],
|
||||||
|
"links": node_hw["links"]}
|
||||||
|
|
||||||
|
mock_redfish_compose_node.return_value = node_hw
|
||||||
|
uuid = 'ea8e2a25-2901-438d-8157-de7ffd68d051'
|
||||||
|
mock_generate_uuid.return_value = uuid
|
||||||
|
|
||||||
|
flavor = flavor_fakes.fake_flavor()
|
||||||
|
mock_get_flavor.return_value = flavor
|
||||||
|
|
||||||
|
result = nodes.Node.compose_node(
|
||||||
|
{"name": node_hw["name"],
|
||||||
|
"description": node_hw["description"],
|
||||||
|
"flavor_id": flavor["uuid"]})
|
||||||
|
expected = nodes.Node._show_node_brief_info(node_hw)
|
||||||
|
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
mock_db_create_composed_node.assert_called_once_with(node_db)
|
||||||
|
mock_get_flavor.assert_called_once_with(flavor["uuid"])
|
||||||
|
|
||||||
@mock.patch("valence.redfish.redfish.get_node_by_id")
|
@mock.patch("valence.redfish.redfish.get_node_by_id")
|
||||||
@mock.patch("valence.db.api.Connection.get_composed_node_by_uuid")
|
@mock.patch("valence.db.api.Connection.get_composed_node_by_uuid")
|
||||||
def test_get_composed_node_by_uuid(
|
def test_get_composed_node_by_uuid(
|
||||||
|
@ -23,7 +23,7 @@ def fake_flavor():
|
|||||||
"type": "DDR2"
|
"type": "DDR2"
|
||||||
},
|
},
|
||||||
"processor": {
|
"processor": {
|
||||||
"total_cores": "10",
|
"total_cores": "2",
|
||||||
"model": "Intel"
|
"model": "Intel"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user