API layer support to node adoption

This patch adds API layer support to node adoption, including the
preview mode of node adoption.

Blueprint: senlin-adopt-function
Change-Id: If670b6f898fcc06d78b6ab5d2cc7fad827e6cbda
This commit is contained in:
tengqm 2017-05-03 23:51:35 -04:00
parent 703c0f4796
commit 88a9f982d9
6 changed files with 116 additions and 1 deletions

View File

@ -24,6 +24,8 @@
"profiles:validate": "",
"nodes:index": "",
"nodes:create": "",
"nodes:adopt": "",
"nodes:adopt_preview": "",
"nodes:get": "",
"nodes:action": "",
"nodes:update": "",

View File

@ -70,6 +70,26 @@ class NodeController(wsgi.Controller):
}
return result
@wsgi.Controller.api_version('1.7')
@util.policy_enforce
def adopt(self, req, body):
"""Adopt a node for management."""
# make sure we don't fall into the preview path
body['preview'] = False
obj = util.parse_request('NodeAdoptRequest', req, body)
node = self.rpc_client.call(req.context, 'node_adopt', obj)
return {'node': node}
@wsgi.Controller.api_version('1.7')
@util.policy_enforce
def adopt_preview(self, req, body):
"""Preview a node adoption."""
# make sure we will fall into the preview path
body['preview'] = True
obj = util.parse_request('NodeAdoptRequest', req, body)
node = self.rpc_client.call(req.context, 'node_adopt_preview', obj)
return {'node_profile': node}
@util.policy_enforce
def get(self, req, node_id):
params = {'identity': node_id}

View File

@ -190,6 +190,14 @@ class API(wsgi.Router):
action="create",
conditions={'method': 'POST'},
success=202)
sub_mapper.connect("node_adopt",
"/nodes/adopt",
action="adopt",
conditions={'method': 'POST'})
sub_mapper.connect("node_adopt_preview",
"/nodes/adopt/preview",
action="adopt_preview",
conditions={'method': 'POST'})
sub_mapper.connect("node_get",
"/nodes/{node_id}",
action="get",

View File

@ -116,7 +116,7 @@ class NodeAdoptRequest(base.SenlinObject):
'identity': fields.StringField(),
'type': fields.StringField(),
'name': fields.NameField(nullable=True),
'cluster': fields.StringField(nullable=True),
'cluster': fields.StringField(nullable=True, default=''),
'role': fields.StringField(nullable=True),
'metadata': fields.JsonField(nullable=True, default={}),
'overrides': fields.JsonField(nullable=True),

View File

@ -409,6 +409,77 @@ class NodeControllerTest(shared.ControllerTest, base.SenlinTestCase):
mock_call.assert_called_once_with(
req.context, 'node_create', mock.ANY)
@mock.patch.object(util, 'parse_request')
@mock.patch.object(rpc_client.EngineClient, 'call')
def test_node_adopt(self, mock_call, mock_parse, mock_enforce):
self._mock_enforce_setup(mock_enforce, 'adopt', True)
body = {
'identity': 'PHYSICAL',
'type': 'RES-TYPE',
'name': 'test_node',
'cluster': 'CLUSTER',
'role': 'ROLE',
'metadata': {'MK': 'MV'},
'overrides': {'NKEY': 'NVAL'},
'snapshot': True,
}
engine_response = {
'id': 'test_node_id',
'name': 'test_node',
'profile_id': 'xxxx-yyyy',
'cluster_id': 'test_cluster_id',
'role': 'ROLE',
'metadata': {'MK': 'MV'},
}
req = self._post('/nodes/adopt', jsonutils.dumps(body),
version='1.7')
obj = mock.Mock()
mock_parse.return_value = obj
mock_call.return_value = engine_response
resp = self.controller.adopt(req, body=body)
self.assertEqual({'node': engine_response}, resp)
mock_parse.assert_called_once_with('NodeAdoptRequest', req, body)
mock_call.assert_called_once_with(req.context, 'node_adopt', mock.ANY)
@mock.patch.object(util, 'parse_request')
@mock.patch.object(rpc_client.EngineClient, 'call')
def test_node_adopt_preview(self, mock_call, mock_parse, mock_enforce):
self._mock_enforce_setup(mock_enforce, 'adopt_preview', True)
body = {
'identity': 'PHYSICAL',
'type': 'RES-TYPE',
'name': 'test_node',
'cluster': 'CLUSTER',
'role': 'ROLE',
'metadata': {'MK': 'MV'},
'overrides': {'NKEY': 'NVAL'},
'snapshot': True,
}
engine_response = {
'id': 'test_node_id',
'name': 'test_node',
'profile_id': 'xxxx-yyyy',
'cluster_id': 'test_cluster_id',
'role': 'ROLE',
'metadata': {'MK': 'MV'},
}
req = self._post('/nodes/adopt/preview', jsonutils.dumps(body),
version='1.7')
obj = mock.Mock()
mock_parse.return_value = obj
mock_call.return_value = engine_response
resp = self.controller.adopt_preview(req, body=body)
self.assertEqual({'node_profile': engine_response}, resp)
mock_parse.assert_called_once_with('NodeAdoptRequest', req, body)
mock_call.assert_called_once_with(req.context, 'node_adopt_preview',
mock.ANY)
@mock.patch.object(util, 'parse_request')
@mock.patch.object(rpc_client.EngineClient, 'call')
def test_node_get_success(self, mock_call, mock_parse, mock_enforce):

View File

@ -268,6 +268,20 @@ class RoutesTest(base.SenlinTestCase):
'success': '202'
})
self.assertRoute(
self.m,
'/nodes/adopt',
'POST',
'adopt',
'NodeController')
self.assertRoute(
self.m,
'/nodes/adopt/preview',
'POST',
'adopt_preview',
'NodeController')
self.assertRoute(
self.m,
'/nodes/bbbb',