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:
Nate Potter 2017-02-14 15:40:11 -08:00
parent 6bc8f689b0
commit 9e0627f2e0
8 changed files with 142 additions and 5 deletions

View File

@ -1,4 +1,17 @@
{
"name": "test_node",
"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"
}
}
}

View File

@ -175,6 +175,12 @@ node_processor_asset:
in: body
required: true
type: array
node_properties:
description: |
Dictionary of properties of a composed node.
in: body
required: false
type: dictionary
node_property:
description: |
Property of composed node including processor , memory , storage info.

View File

@ -29,6 +29,8 @@ Request
- name: node_request_name
- description: node_request_description
- flavor_id: flavor_uuid
- properties: node_properties
**Example Node creation request:**

View File

@ -24,6 +24,11 @@ def list_flavors():
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):
flavor = db_api.Connection.create_flavor(values)
return flavor.as_dict()

View File

@ -15,6 +15,7 @@
import six
from valence.common import utils
from valence.controller import flavors
from valence.db import api as db_api
from valence.redfish import redfish
@ -26,6 +27,32 @@ class Node(object):
return {key: node_info[key] for key in six.iterkeys(node_info)
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
def compose_node(cls, request_body):
"""Compose new node
@ -34,8 +61,26 @@ class Node(object):
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
composed_node = redfish.compose_node(request_body)
composed_node = redfish.compose_node(compose_request)
composed_node["uuid"] = utils.generate_uuid()

View File

@ -46,7 +46,7 @@ def get_test_composed_node(**kwargs):
'vlans': [{'status': 'Enabled',
'vlanid': 99}]}],
'processor': [{'instruction_set': None,
'model': None,
'model': 'None',
'speed_mhz': 3700,
'total_core': 0}]})
'total_core': 2}]})
}

View File

@ -19,6 +19,7 @@ import mock
from valence.controller import nodes
from valence.tests.unit.controller import fakes
from valence.tests.unit.db import utils as test_utils
from valence.tests.unit.fakes import flavor_fakes
class TestAPINodes(unittest.TestCase):
@ -39,6 +40,37 @@ class TestAPINodes(unittest.TestCase):
self.assertEqual(expected,
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.common.utils.generate_uuid")
@mock.patch("valence.redfish.redfish.compose_node")
@ -55,12 +87,46 @@ class TestAPINodes(unittest.TestCase):
uuid = 'ea8e2a25-2901-438d-8157-de7ffd68d051'
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)
self.assertEqual(expected, result)
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.db.api.Connection.get_composed_node_by_uuid")
def test_get_composed_node_by_uuid(

View File

@ -23,7 +23,7 @@ def fake_flavor():
"type": "DDR2"
},
"processor": {
"total_cores": "10",
"total_cores": "2",
"model": "Intel"
}
}