Add Validation for Node Manage/Action API's
Partially-Implements blueprint validation Change-Id: If10e37e0036c88a4bd0b183793e4344d8c257b67
This commit is contained in:
parent
a42b5a688f
commit
542f3ced2f
@ -332,7 +332,7 @@ Response
|
|||||||
Manage Node
|
Manage Node
|
||||||
===========
|
===========
|
||||||
|
|
||||||
.. rest_method:: POST /v1/nodes/managed
|
.. rest_method:: POST /v1/nodes/manage
|
||||||
|
|
||||||
Manage a composed node already existing in the RSD rack by creating a
|
Manage a composed node already existing in the RSD rack by creating a
|
||||||
Valence database entry for it, allowing Valence to perform all operations
|
Valence database entry for it, allowing Valence to perform all operations
|
||||||
|
@ -48,14 +48,16 @@ class Node(Resource):
|
|||||||
|
|
||||||
class NodeAction(Resource):
|
class NodeAction(Resource):
|
||||||
|
|
||||||
|
@validator.check_input('node_action_schema')
|
||||||
def post(self, node_uuid):
|
def post(self, node_uuid):
|
||||||
return utils.make_response(
|
return utils.make_response(
|
||||||
http_client.OK,
|
http_client.NO_CONTENT,
|
||||||
nodes.Node.node_action(node_uuid, request.get_json()))
|
nodes.Node.node_action(node_uuid, request.get_json()))
|
||||||
|
|
||||||
|
|
||||||
class NodeManage(Resource):
|
class NodeManage(Resource):
|
||||||
|
|
||||||
|
@validator.check_input('node_manage_schema')
|
||||||
def post(self):
|
def post(self):
|
||||||
return utils.make_response(
|
return utils.make_response(
|
||||||
http_client.OK, nodes.Node.manage_node(request.get_json()))
|
http_client.OK, nodes.Node.manage_node(request.get_json()))
|
||||||
|
@ -191,19 +191,6 @@ class Node(object):
|
|||||||
param request_body: parameter of node action
|
param request_body: parameter of node action
|
||||||
return: message of this deletion
|
return: message of this deletion
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Get node detail from db, and map node uuid to index
|
# Get node detail from db, and map node uuid to index
|
||||||
index = db_api.Connection.get_composed_node_by_uuid(node_uuid).index
|
index = db_api.Connection.get_composed_node_by_uuid(node_uuid).index
|
||||||
|
|
||||||
# TODO(lin.yang): should validate request body whether follow specifc
|
|
||||||
# format, like
|
|
||||||
# {
|
|
||||||
# "Reset": {
|
|
||||||
# "Type": "On"
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# Should rework this part after basic validation framework for api
|
|
||||||
# input is done.
|
|
||||||
# https://review.openstack.org/#/c/422547/
|
|
||||||
|
|
||||||
return redfish.node_action(index, request_body)
|
return redfish.node_action(index, request_body)
|
||||||
|
@ -3,6 +3,7 @@ import json
|
|||||||
|
|
||||||
import mock
|
import mock
|
||||||
from oslotest import base
|
from oslotest import base
|
||||||
|
from six.moves import http_client
|
||||||
|
|
||||||
from valence.api import app as flask_app
|
from valence.api import app as flask_app
|
||||||
from valence.common import constants
|
from valence.common import constants
|
||||||
@ -32,7 +33,7 @@ class TestFlavorApi(TestApiValidation):
|
|||||||
response = self.app.post('/v1/flavors',
|
response = self.app.post('/v1/flavors',
|
||||||
content_type='application/json',
|
content_type='application/json',
|
||||||
data=json.dumps(flavor))
|
data=json.dumps(flavor))
|
||||||
self.assertEqual(200, response.status_code)
|
self.assertEqual(http_client.OK, response.status_code)
|
||||||
mock_create.assert_called_once_with(flavor)
|
mock_create.assert_called_once_with(flavor)
|
||||||
|
|
||||||
def test_flavor_create_incorrect_param(self):
|
def test_flavor_create_incorrect_param(self):
|
||||||
@ -44,7 +45,7 @@ class TestFlavorApi(TestApiValidation):
|
|||||||
content_type='application/json',
|
content_type='application/json',
|
||||||
data=json.dumps(self.flavor))
|
data=json.dumps(self.flavor))
|
||||||
response = json.loads(response.data.decode())
|
response = json.loads(response.data.decode())
|
||||||
self.assertEqual(400, response['status'])
|
self.assertEqual(http_client.BAD_REQUEST, response['status'])
|
||||||
self.assertEqual('ValidationError', response['code'])
|
self.assertEqual('ValidationError', response['code'])
|
||||||
|
|
||||||
# Test invalid key
|
# Test invalid key
|
||||||
@ -53,7 +54,7 @@ class TestFlavorApi(TestApiValidation):
|
|||||||
content_type='application/json',
|
content_type='application/json',
|
||||||
data=json.dumps(self.flavor))
|
data=json.dumps(self.flavor))
|
||||||
response = json.loads(response.data.decode())
|
response = json.loads(response.data.decode())
|
||||||
self.assertEqual(400, response['status'])
|
self.assertEqual(http_client.BAD_REQUEST, response['status'])
|
||||||
self.assertEqual('ValidationError', response['code'])
|
self.assertEqual('ValidationError', response['code'])
|
||||||
|
|
||||||
|
|
||||||
@ -84,7 +85,7 @@ class TestPodmanagerApi(TestApiValidation):
|
|||||||
response = self.app.post('/v1/pod_managers',
|
response = self.app.post('/v1/pod_managers',
|
||||||
content_type='application/json',
|
content_type='application/json',
|
||||||
data=json.dumps(values))
|
data=json.dumps(values))
|
||||||
self.assertEqual(200, response.status_code)
|
self.assertEqual(http_client.OK, response.status_code)
|
||||||
|
|
||||||
def test_check_creation_incomplete_parameters(self):
|
def test_check_creation_incomplete_parameters(self):
|
||||||
incomplete_values = {
|
incomplete_values = {
|
||||||
@ -95,7 +96,7 @@ class TestPodmanagerApi(TestApiValidation):
|
|||||||
content_type='application/json',
|
content_type='application/json',
|
||||||
data=json.dumps(incomplete_values))
|
data=json.dumps(incomplete_values))
|
||||||
response = json.loads(response.data.decode())
|
response = json.loads(response.data.decode())
|
||||||
self.assertEqual(400, response['status'])
|
self.assertEqual(http_client.BAD_REQUEST, response['status'])
|
||||||
self.assertEqual('ValidationError', response['code'])
|
self.assertEqual('ValidationError', response['code'])
|
||||||
|
|
||||||
def test_check_creation_invalid_authentication(self):
|
def test_check_creation_invalid_authentication(self):
|
||||||
@ -111,7 +112,7 @@ class TestPodmanagerApi(TestApiValidation):
|
|||||||
content_type='application/json',
|
content_type='application/json',
|
||||||
data=json.dumps(invalid_auth_values))
|
data=json.dumps(invalid_auth_values))
|
||||||
response = json.loads(response.data.decode())
|
response = json.loads(response.data.decode())
|
||||||
self.assertEqual(400, response['status'])
|
self.assertEqual(http_client.BAD_REQUEST, response['status'])
|
||||||
self.assertEqual('ValidationError', response['code'])
|
self.assertEqual('ValidationError', response['code'])
|
||||||
|
|
||||||
|
|
||||||
@ -136,7 +137,7 @@ class TestNodeApi(TestApiValidation):
|
|||||||
resp = self.app.post('/v1/nodes',
|
resp = self.app.post('/v1/nodes',
|
||||||
content_type='application/json',
|
content_type='application/json',
|
||||||
data=json.dumps(req))
|
data=json.dumps(req))
|
||||||
self.assertEqual(200, resp.status_code)
|
self.assertEqual(http_client.OK, resp.status_code)
|
||||||
|
|
||||||
@mock.patch('valence.controller.nodes.Node.compose_node')
|
@mock.patch('valence.controller.nodes.Node.compose_node')
|
||||||
def test_compose_request_using_flavor(self, mock_compose):
|
def test_compose_request_using_flavor(self, mock_compose):
|
||||||
@ -148,7 +149,7 @@ class TestNodeApi(TestApiValidation):
|
|||||||
resp = self.app.post('/v1/nodes',
|
resp = self.app.post('/v1/nodes',
|
||||||
content_type='application/json',
|
content_type='application/json',
|
||||||
data=json.dumps(req))
|
data=json.dumps(req))
|
||||||
self.assertEqual(200, resp.status_code)
|
self.assertEqual(http_client.OK, resp.status_code)
|
||||||
|
|
||||||
def test_compose_request_invalid_params(self):
|
def test_compose_request_invalid_params(self):
|
||||||
req = {
|
req = {
|
||||||
@ -158,5 +159,54 @@ class TestNodeApi(TestApiValidation):
|
|||||||
content_type='application/json',
|
content_type='application/json',
|
||||||
data=json.dumps(req))
|
data=json.dumps(req))
|
||||||
response = json.loads(resp.data.decode())
|
response = json.loads(resp.data.decode())
|
||||||
self.assertEqual(400, response['status'])
|
self.assertEqual(http_client.BAD_REQUEST, response['status'])
|
||||||
|
self.assertEqual('ValidationError', response['code'])
|
||||||
|
|
||||||
|
@mock.patch('valence.controller.nodes.Node.manage_node')
|
||||||
|
def test_node_manage_request(self, mock_manage):
|
||||||
|
req = {"node_index": "fake-index"}
|
||||||
|
mock_manage.return_value = {"uuid": "ea8e2a25-2901-438d-8157-de7ffd",
|
||||||
|
"links": "fake-links",
|
||||||
|
"name": "fake-node",
|
||||||
|
"index": "fake-index"}
|
||||||
|
resp = self.app.post('/v1/nodes/manage',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(req))
|
||||||
|
mock_manage.assert_called_once_with(req)
|
||||||
|
self.assertEqual(http_client.OK, resp.status_code)
|
||||||
|
|
||||||
|
def test_node_manage_request_invalid(self):
|
||||||
|
req = {"node_id": "fake-index"}
|
||||||
|
resp = self.app.post('/v1/nodes/manage',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(req))
|
||||||
|
response = json.loads(resp.data.decode())
|
||||||
|
self.assertEqual(http_client.BAD_REQUEST, response['status'])
|
||||||
|
self.assertEqual('ValidationError', response['code'])
|
||||||
|
|
||||||
|
@mock.patch('valence.controller.nodes.Node.node_action')
|
||||||
|
def test_node_action_request(self, mock_action):
|
||||||
|
req = {
|
||||||
|
"Reset": {
|
||||||
|
"Type": "On"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mock_action.return_value = None
|
||||||
|
resp = self.app.post('/v1/nodes/fake-node/action',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(req))
|
||||||
|
mock_action.assert_called_once_with('fake-node', req)
|
||||||
|
self.assertEqual(http_client.NO_CONTENT, resp.status_code)
|
||||||
|
|
||||||
|
def test_node_action_request_invalid(self):
|
||||||
|
req = {
|
||||||
|
"Boot": {
|
||||||
|
"Type": "On"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resp = self.app.post('/v1/nodes/fake-node/action',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(req))
|
||||||
|
response = json.loads(resp.data.decode())
|
||||||
|
self.assertEqual(http_client.BAD_REQUEST, response['status'])
|
||||||
self.assertEqual('ValidationError', response['code'])
|
self.assertEqual('ValidationError', response['code'])
|
||||||
|
@ -68,7 +68,6 @@ podmanager_schema = {
|
|||||||
'additionalProperties': False,
|
'additionalProperties': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
jsonschema.Draft4Validator.check_schema(podmanager_schema)
|
jsonschema.Draft4Validator.check_schema(podmanager_schema)
|
||||||
|
|
||||||
compose_node_with_flavor = {
|
compose_node_with_flavor = {
|
||||||
@ -91,6 +90,54 @@ compose_node_schema = {
|
|||||||
|
|
||||||
jsonschema.Draft4Validator.check_schema(compose_node_schema)
|
jsonschema.Draft4Validator.check_schema(compose_node_schema)
|
||||||
|
|
||||||
|
node_manage_schema = {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'node_index': {'type': 'string'},
|
||||||
|
},
|
||||||
|
'required': ['node_index'],
|
||||||
|
'additionalProperties': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonschema.Draft4Validator.check_schema(node_manage_schema)
|
||||||
|
|
||||||
|
node_action_schema = {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'Boot': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'Enabled': {
|
||||||
|
'enum': ['Once', 'Continuous']
|
||||||
|
},
|
||||||
|
'Target': {
|
||||||
|
'enum': ['Pxe', 'Hdd', 'None']
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'required': ['Enabled', 'Target'],
|
||||||
|
'additionalProperties': False,
|
||||||
|
},
|
||||||
|
'Reset': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'Type': {
|
||||||
|
'enum': ['On', 'ForceOn', 'ForceOff', 'GracefulRestart']
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'required': ['Type'],
|
||||||
|
'additionalProperties': False,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'oneOf': [
|
||||||
|
{'required': ['Boot']},
|
||||||
|
{'required': ['Reset']}],
|
||||||
|
'additionalProperties': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonschema.Draft4Validator.check_schema(node_action_schema)
|
||||||
|
|
||||||
SCHEMAS = {'flavor_schema': flavor_schema,
|
SCHEMAS = {'flavor_schema': flavor_schema,
|
||||||
'podmanager_schema': podmanager_schema,
|
'podmanager_schema': podmanager_schema,
|
||||||
'compose_node_schema': compose_node_schema, }
|
'compose_node_schema': compose_node_schema,
|
||||||
|
'node_manage_schema': node_manage_schema,
|
||||||
|
'node_action_schema': node_action_schema, }
|
||||||
|
Loading…
Reference in New Issue
Block a user