Add Rack API
This commit adds API and corresponding controller functions for viewing rack resources. Change-Id: I66fd2f9cfe30b7a87ee4ea16a9f8027c34d1d0e6 Closes-bug: #1633443
This commit is contained in:
parent
6a0ae4e05b
commit
d11c1aef9b
15
api-ref/source/mockup/rack-get-response.json
Normal file
15
api-ref/source/mockup/rack-get-response.json
Normal file
@ -0,0 +1,15 @@
|
||||
[
|
||||
{
|
||||
"description": "Rack created by PODM",
|
||||
"id": "1",
|
||||
"manufacturer": "Intel",
|
||||
"model": "RSD_1",
|
||||
"name": "Rack 1",
|
||||
"serial_number": "12345",
|
||||
"systems": [
|
||||
"2cd33e50-0e7a-11e7-8c14-c5fab3f6ca28",
|
||||
"2a911680-0e7a-11e7-8c14-c5fab3f6ca28",
|
||||
"4cadbee1-fe07-11e6-8c14-c5fab3f6ca28"
|
||||
]
|
||||
}
|
||||
]
|
19
api-ref/source/mockup/rack-list-response.json
Normal file
19
api-ref/source/mockup/rack-list-response.json
Normal file
@ -0,0 +1,19 @@
|
||||
[
|
||||
{
|
||||
"id": "1",
|
||||
"name": "Rack 1",
|
||||
"systems": [
|
||||
"2cd33e50-0e7a-11e7-8c14-c5fab3f6ca28",
|
||||
"2a911680-0e7a-11e7-8c14-c5fab3f6ca28",
|
||||
"4cadbee1-fe07-11e6-8c14-c5fab3f6ca28"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "Rack 2",
|
||||
"systems": [
|
||||
"7ac441b3-a4a1-44f4-8b38-469492cbfb61",
|
||||
"3bf332e4-100c-11e7-93ae-92361f002671"
|
||||
]
|
||||
}
|
||||
]
|
@ -285,6 +285,45 @@ pod_redfish_link:
|
||||
pod_status:
|
||||
description: |
|
||||
Pod manager status
|
||||
rack_id:
|
||||
description: |
|
||||
The ID of a hardware rack.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
rack_name:
|
||||
description: |
|
||||
Name of a hardware rack.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
rack_systems:
|
||||
description: |
|
||||
Compute systems contained by a rack.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
rack_manufacturer:
|
||||
description: |
|
||||
The manufacturer for a rack.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
rack_model:
|
||||
description: |
|
||||
The model for a rack.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
rack_description:
|
||||
description: |
|
||||
The description of a rack.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
rack_serial_number:
|
||||
description: |
|
||||
The serial number of a rack.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
|
75
api-ref/source/valence-api-v1-racks.inc
Normal file
75
api-ref/source/valence-api-v1-racks.inc
Normal file
@ -0,0 +1,75 @@
|
||||
.. -*- rst -*-
|
||||
|
||||
====
|
||||
Rack
|
||||
====
|
||||
|
||||
List, Searching of hardware racks through the ``/v1/racks`` resource.
|
||||
|
||||
List Racks
|
||||
==========
|
||||
|
||||
.. rest_method:: GET /v1/racks/
|
||||
|
||||
Return a list of Racks.
|
||||
Some filtering is possible by passing in flags with the request.
|
||||
By default, this query will return racks with id, name, location and
|
||||
contained compute systems.
|
||||
|
||||
Normal response codes: 200
|
||||
Error response codes: badRequest(400), unauthorized(401), forbidden(403)
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- id: rack_id
|
||||
- name: rack_name
|
||||
- systems: rack_systems
|
||||
|
||||
**Example list of Racks:**
|
||||
|
||||
.. literalinclude:: mockup/rack-list-response.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
Display Rack Details
|
||||
====================
|
||||
|
||||
.. rest_method:: GET /v1/racks/{rack_id}
|
||||
|
||||
Shows details for a Rack.
|
||||
This will return the full representation of the resources.
|
||||
|
||||
Normal response codes: 200
|
||||
|
||||
Error response codes: badRequest(400), unauthorized(401), forbidden(403)
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- id: rack_id
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- id: rack_id
|
||||
- name: rack_name
|
||||
- systems: rack_systems
|
||||
- manufacturer: rack_manufacturer
|
||||
- model: rack_model
|
||||
- description: rack_description
|
||||
- serial_number: rack_serial_number
|
||||
|
||||
**Example JSON representation of a Rack:**
|
||||
|
||||
.. literalinclude:: mockup/rack-get-response.json
|
||||
:language: javascript
|
@ -24,6 +24,7 @@ import valence.api.root as api_root
|
||||
import valence.api.v1.flavors as v1_flavors
|
||||
import valence.api.v1.nodes as v1_nodes
|
||||
import valence.api.v1.podmanagers as v1_podmanagers
|
||||
import valence.api.v1.racks as v1_racks
|
||||
import valence.api.v1.storages as v1_storages
|
||||
import valence.api.v1.systems as v1_systems
|
||||
import valence.api.v1.version as v1_version
|
||||
@ -65,6 +66,10 @@ api.add_resource(api_root.Root, '/', endpoint='root')
|
||||
# V1 Root operations
|
||||
api.add_resource(v1_version.V1, '/v1', endpoint='v1')
|
||||
|
||||
# Rack operations
|
||||
api.add_resource(v1_racks.RackList, '/v1/racks', endpoint='racks')
|
||||
api.add_resource(v1_racks.Rack, '/v1/racks/<string:rack_id>', endpoint='rack')
|
||||
|
||||
# Node(s) operations
|
||||
api.add_resource(v1_nodes.Nodes, '/v1/nodes', endpoint='nodes')
|
||||
api.add_resource(v1_nodes.Node,
|
||||
|
38
valence/api/v1/racks.py
Normal file
38
valence/api/v1/racks.py
Normal file
@ -0,0 +1,38 @@
|
||||
# Copyright (c) 2016 Intel, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
|
||||
from flask import request
|
||||
import flask_restful
|
||||
from six.moves import http_client
|
||||
|
||||
from valence.common import utils
|
||||
from valence.redfish import redfish
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RackList(flask_restful.Resource):
|
||||
|
||||
def get(self):
|
||||
return utils.make_response(
|
||||
http_client.OK, redfish.list_racks(request.get_json()))
|
||||
|
||||
|
||||
class Rack(flask_restful.Resource):
|
||||
|
||||
def get(self, rack_id):
|
||||
return utils.make_response(
|
||||
http_client.OK, redfish.show_rack(rack_id))
|
@ -13,7 +13,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
||||
@ -81,33 +80,68 @@ def send_request(resource, method="GET", **kwargs):
|
||||
|
||||
|
||||
def filter_chassis(jsonContent, filterCondition):
|
||||
returnJSONObj = {}
|
||||
returnMembers = []
|
||||
members = jsonContent['Members']
|
||||
for member in members:
|
||||
resource = member['@odata.id']
|
||||
resp = send_request(resource)
|
||||
memberJsonObj = resp.json()
|
||||
chassisType = memberJsonObj['ChassisType']
|
||||
member_detail = resp.json()
|
||||
chassisType = member_detail['ChassisType']
|
||||
if chassisType == filterCondition:
|
||||
returnMembers.append(member)
|
||||
returnJSONObj["Members"] = returnMembers
|
||||
returnJSONObj["Members@odata.count"] = len(returnMembers)
|
||||
return returnJSONObj
|
||||
returnMembers.append(member_detail)
|
||||
return returnMembers
|
||||
|
||||
|
||||
def racks():
|
||||
def list_racks(filters={}, show_detail=False):
|
||||
chassis_url = get_base_resource_url("Chassis")
|
||||
jsonContent = send_request(chassis_url)
|
||||
racks = filter_chassis(jsonContent, "Rack")
|
||||
return json.dumps(racks)
|
||||
resp = send_request(chassis_url)
|
||||
json_content = resp.json()
|
||||
raw_racks = filter_chassis(json_content, "Rack")
|
||||
racks = []
|
||||
filterPassed = True
|
||||
|
||||
for rack in raw_racks:
|
||||
|
||||
if any(filters):
|
||||
filterPassed = utils.match_conditions(rack, filters)
|
||||
if not filterPassed:
|
||||
continue
|
||||
|
||||
rack_info = {}
|
||||
|
||||
rack_id = rack["Id"]
|
||||
rack_name = rack["Name"]
|
||||
rack_systems = get_systems_in_chassis(rack)
|
||||
rack_info.update({"id": rack_id, "name": rack_name,
|
||||
"systems": rack_systems})
|
||||
if show_detail:
|
||||
manufacturer = rack["Manufacturer"]
|
||||
model = rack["Model"]
|
||||
description = rack["Description"]
|
||||
serial_number = rack["SerialNumber"]
|
||||
rack_info.update({"manufacturer": manufacturer,
|
||||
"model": model,
|
||||
"description": description,
|
||||
"serial_number": serial_number})
|
||||
racks.append(rack_info)
|
||||
return racks
|
||||
|
||||
|
||||
def pods():
|
||||
chassis_url = get_base_resource_url("Chassis")
|
||||
jsonContent = send_request(chassis_url)
|
||||
pods = filter_chassis(jsonContent, "Pod")
|
||||
return json.dumps(pods)
|
||||
def show_rack(rack_id):
|
||||
return list_racks({"Id": rack_id}, show_detail=True)
|
||||
|
||||
|
||||
def get_systems_in_chassis(chassis, total_systems=[]):
|
||||
for chassis_link in chassis["Links"]["Contains"]:
|
||||
resp = send_request(chassis_link["@odata.id"])
|
||||
chassis = resp.json()
|
||||
total_systems = get_systems_in_chassis(chassis, total_systems)
|
||||
for system_link in chassis["Links"]["ComputerSystems"]:
|
||||
resp = send_request(system_link["@odata.id"])
|
||||
system = resp.json()
|
||||
if system["UUID"] not in total_systems:
|
||||
total_systems.append(system["UUID"])
|
||||
return total_systems
|
||||
|
||||
|
||||
def pod_status(pod_url, username, password):
|
||||
|
@ -33,6 +33,7 @@ class TestRoute(unittest.TestCase):
|
||||
|
||||
self.assertEqual(self.api.owns_endpoint('root'), True)
|
||||
self.assertEqual(self.api.owns_endpoint('v1'), True)
|
||||
self.assertEqual(self.api.owns_endpoint('racks'), True)
|
||||
self.assertEqual(self.api.owns_endpoint('nodes'), True)
|
||||
self.assertEqual(self.api.owns_endpoint('node'), True)
|
||||
self.assertEqual(self.api.owns_endpoint('nodes_storages'), True)
|
||||
|
@ -341,3 +341,39 @@ def fake_assemble_node_failed():
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def fake_rack_list():
|
||||
return [
|
||||
{
|
||||
"Description": "Rack created by PODM",
|
||||
"Id": "2",
|
||||
"Manufacturer": "Intel",
|
||||
"Model": "RSD_1",
|
||||
"Name": "Rack 1",
|
||||
"SerialNumber": "12345",
|
||||
"Links": {
|
||||
"Contains": [],
|
||||
"ComputerSystems": [
|
||||
{"@odata.id": "/redfish/v1/Systems/1"},
|
||||
{"@odata.id": "/redfish/v1/Systems/2"},
|
||||
{"@odata.id": "/redfish/v1/Systems/3"}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Description": "Rack created by PODM",
|
||||
"Id": "3",
|
||||
"Manufacturer": "Intel",
|
||||
"Model": "RSD_1",
|
||||
"Name": "Rack 2",
|
||||
"SerialNumber": "12346",
|
||||
"Links": {
|
||||
"Contains": [],
|
||||
"ComputerSystems": [
|
||||
{"@odata.id": "/redfish/v1/Systems/4"},
|
||||
{"@odata.id": "/redfish/v1/Systems/5"}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -119,10 +119,18 @@ class TestRedfish(TestCase):
|
||||
[{"@odata.id": "1"},
|
||||
{"@odata.id": "2"},
|
||||
{"@odata.id": "3"}]}
|
||||
expected = {'Members': [
|
||||
{u'@odata.id': u'2'},
|
||||
{u'@odata.id': u'3'}
|
||||
], 'Members@odata.count': 2}
|
||||
expected = [
|
||||
{
|
||||
"ChassisType": "Rack",
|
||||
"Name": "Rack 1",
|
||||
"Id": "2"
|
||||
},
|
||||
{
|
||||
"ChassisType": "Rack",
|
||||
"Name": "Rack 2",
|
||||
"Id": "3"
|
||||
}
|
||||
]
|
||||
result = redfish.filter_chassis(chassis, "Rack")
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
@ -576,3 +584,81 @@ class TestRedfish(TestCase):
|
||||
redfish.node_action("1", {"Reset": {"Type": "On"}})
|
||||
|
||||
mock_reset_node.assert_called_once_with("1", {"Reset": {"Type": "On"}})
|
||||
|
||||
@mock.patch('valence.redfish.redfish.get_systems_in_chassis')
|
||||
@mock.patch('valence.redfish.redfish.get_base_resource_url')
|
||||
@mock.patch('valence.redfish.redfish.filter_chassis')
|
||||
@mock.patch('valence.redfish.redfish.send_request')
|
||||
def test_list_racks(self, mock_request, mock_filter, mock_base_url,
|
||||
mock_system_list):
|
||||
mock_base_url.return_value = "/redfish/v1/Chassis"
|
||||
fake_chassis_list = fakes.fake_chassis_list()
|
||||
mock_request.return_value = (
|
||||
fakes.mock_request_get(fake_chassis_list, "200"))
|
||||
mock_filter.return_value = fakes.fake_rack_list()
|
||||
mock_system_list.side_effect = [
|
||||
[
|
||||
"2cd33e50-0e7a-11e7-8c14-c5fab3f6ca28",
|
||||
"2a911680-0e7a-11e7-8c14-c5fab3f6ca28",
|
||||
"4cadbee1-fe07-11e6-8c14-c5fab3f6ca28"
|
||||
],
|
||||
[
|
||||
"7ac441b3-a4a1-44f4-8b38-469492cbfb61",
|
||||
"3bf332e4-100c-11e7-93ae-92361f002671"
|
||||
]
|
||||
]
|
||||
expected = [
|
||||
{
|
||||
"id": "2",
|
||||
"name": "Rack 1",
|
||||
"systems": [
|
||||
"2cd33e50-0e7a-11e7-8c14-c5fab3f6ca28",
|
||||
"2a911680-0e7a-11e7-8c14-c5fab3f6ca28",
|
||||
"4cadbee1-fe07-11e6-8c14-c5fab3f6ca28"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"name": "Rack 2",
|
||||
"systems": [
|
||||
"7ac441b3-a4a1-44f4-8b38-469492cbfb61",
|
||||
"3bf332e4-100c-11e7-93ae-92361f002671"
|
||||
]
|
||||
}
|
||||
]
|
||||
result = redfish.list_racks()
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
@mock.patch('valence.redfish.redfish.get_systems_in_chassis')
|
||||
@mock.patch('valence.redfish.redfish.get_base_resource_url')
|
||||
@mock.patch('valence.redfish.redfish.filter_chassis')
|
||||
@mock.patch('valence.redfish.redfish.send_request')
|
||||
def test_show_rack(self, mock_request, mock_filter, mock_base_url,
|
||||
mock_system_list):
|
||||
mock_base_url.return_value = "/redfish/v1/Chassis"
|
||||
fake_chassis_list = fakes.fake_chassis_list()
|
||||
mock_request.return_value = (
|
||||
fakes.mock_request_get(fake_chassis_list, "200"))
|
||||
mock_filter.return_value = fakes.fake_rack_list()
|
||||
mock_system_list.return_value = [
|
||||
"2cd33e50-0e7a-11e7-8c14-c5fab3f6ca28",
|
||||
"2a911680-0e7a-11e7-8c14-c5fab3f6ca28",
|
||||
"4cadbee1-fe07-11e6-8c14-c5fab3f6ca28"
|
||||
]
|
||||
expected = [
|
||||
{
|
||||
"description": "Rack created by PODM",
|
||||
"id": "2",
|
||||
"manufacturer": "Intel",
|
||||
"model": "RSD_1",
|
||||
"name": "Rack 1",
|
||||
"serial_number": "12345",
|
||||
"systems": [
|
||||
"2cd33e50-0e7a-11e7-8c14-c5fab3f6ca28",
|
||||
"2a911680-0e7a-11e7-8c14-c5fab3f6ca28",
|
||||
"4cadbee1-fe07-11e6-8c14-c5fab3f6ca28"
|
||||
]
|
||||
}
|
||||
]
|
||||
result = redfish.show_rack("2")
|
||||
self.assertEqual(expected, result)
|
||||
|
Loading…
Reference in New Issue
Block a user