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:
parent
703c0f4796
commit
88a9f982d9
|
@ -24,6 +24,8 @@
|
|||
"profiles:validate": "",
|
||||
"nodes:index": "",
|
||||
"nodes:create": "",
|
||||
"nodes:adopt": "",
|
||||
"nodes:adopt_preview": "",
|
||||
"nodes:get": "",
|
||||
"nodes:action": "",
|
||||
"nodes:update": "",
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Reference in New Issue