Add node list support
This adds support for listing node names from resource providers, which will only available for admins. Partially Implements: bp node-aggregate Change-Id: I414bf176302fc076288e6a6fbfd88a7090541622
This commit is contained in:
parent
9627106519
commit
8a8dc20660
32
api-ref/source/v1/nodes.inc
Normal file
32
api-ref/source/v1/nodes.inc
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
.. -*- rst -*-
|
||||||
|
|
||||||
|
===============
|
||||||
|
Compute Nodes
|
||||||
|
===============
|
||||||
|
|
||||||
|
Lists compute nodes.
|
||||||
|
|
||||||
|
List Compute Node information
|
||||||
|
=============================
|
||||||
|
|
||||||
|
.. rest_method:: GET /nodes
|
||||||
|
|
||||||
|
Lists compute nodes, including name.
|
||||||
|
|
||||||
|
Normal response codes: 200
|
||||||
|
|
||||||
|
Error response codes: unauthorized(401), forbidden(403)
|
||||||
|
|
||||||
|
Response
|
||||||
|
--------
|
||||||
|
|
||||||
|
.. rest_parameters:: parameters.yaml
|
||||||
|
|
||||||
|
- nodes: nodes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
||||||
|
**Example List compute node information**
|
||||||
|
|
||||||
|
.. literalinclude:: samples/nodes/node-list-resp.json
|
||||||
|
:language: javascript
|
@ -435,6 +435,12 @@ nics:
|
|||||||
in: body
|
in: body
|
||||||
required: true
|
required: true
|
||||||
type: dict
|
type: dict
|
||||||
|
nodes:
|
||||||
|
description: |
|
||||||
|
The compute node name list.
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
type: dict
|
||||||
personality:
|
personality:
|
||||||
description: |
|
description: |
|
||||||
The file path and contents, text only, to inject into the server at launch. The
|
The file path and contents, text only, to inject into the server at launch. The
|
||||||
|
7
api-ref/source/v1/samples/nodes/node-list-resp.json
Normal file
7
api-ref/source/v1/samples/nodes/node-list-resp.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"nodes" : [
|
||||||
|
"node-0",
|
||||||
|
"node-1",
|
||||||
|
"node-2"
|
||||||
|
]
|
||||||
|
}
|
@ -29,6 +29,7 @@ from mogan.api.controllers.v1 import aggregates
|
|||||||
from mogan.api.controllers.v1 import availability_zone
|
from mogan.api.controllers.v1 import availability_zone
|
||||||
from mogan.api.controllers.v1 import flavors
|
from mogan.api.controllers.v1 import flavors
|
||||||
from mogan.api.controllers.v1 import keypairs
|
from mogan.api.controllers.v1 import keypairs
|
||||||
|
from mogan.api.controllers.v1 import nodes
|
||||||
from mogan.api.controllers.v1 import servers
|
from mogan.api.controllers.v1 import servers
|
||||||
from mogan.api import expose
|
from mogan.api import expose
|
||||||
|
|
||||||
@ -54,6 +55,9 @@ class V1(base.APIBase):
|
|||||||
aggregates = [link.Link]
|
aggregates = [link.Link]
|
||||||
"""Links to the aggregates resource"""
|
"""Links to the aggregates resource"""
|
||||||
|
|
||||||
|
nodes = [link.Link]
|
||||||
|
"""Links to the nodes resource"""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def convert():
|
def convert():
|
||||||
v1 = V1()
|
v1 = V1()
|
||||||
@ -96,6 +100,14 @@ class V1(base.APIBase):
|
|||||||
'aggregates', '',
|
'aggregates', '',
|
||||||
bookmark=True)
|
bookmark=True)
|
||||||
]
|
]
|
||||||
|
v1.nodes = [link.Link.make_link('self',
|
||||||
|
pecan.request.public_url,
|
||||||
|
'nodes', ''),
|
||||||
|
link.Link.make_link('bookmark',
|
||||||
|
pecan.request.public_url,
|
||||||
|
'nodes', '',
|
||||||
|
bookmark=True)
|
||||||
|
]
|
||||||
return v1
|
return v1
|
||||||
|
|
||||||
|
|
||||||
@ -107,6 +119,7 @@ class Controller(rest.RestController):
|
|||||||
availability_zones = availability_zone.AvailabilityZoneController()
|
availability_zones = availability_zone.AvailabilityZoneController()
|
||||||
keypairs = keypairs.KeyPairController()
|
keypairs = keypairs.KeyPairController()
|
||||||
aggregates = aggregates.AggregateController()
|
aggregates = aggregates.AggregateController()
|
||||||
|
nodes = nodes.NodeController()
|
||||||
|
|
||||||
@expose.expose(V1)
|
@expose.expose(V1)
|
||||||
def get(self):
|
def get(self):
|
||||||
|
46
mogan/api/controllers/v1/nodes.py
Normal file
46
mogan/api/controllers/v1/nodes.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# Copyright 2017 Huawei Technologies Co.,LTD.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 pecan
|
||||||
|
from pecan import rest
|
||||||
|
from wsme import types as wtypes
|
||||||
|
|
||||||
|
from mogan.api.controllers import base
|
||||||
|
from mogan.api import expose
|
||||||
|
from mogan.common import policy
|
||||||
|
|
||||||
|
|
||||||
|
class Nodes(base.APIBase):
|
||||||
|
"""API representation of a collection of nodes."""
|
||||||
|
|
||||||
|
nodes = [wtypes.text]
|
||||||
|
"""A list containing compute node names"""
|
||||||
|
|
||||||
|
|
||||||
|
class NodeController(rest.RestController):
|
||||||
|
"""REST controller for Node."""
|
||||||
|
|
||||||
|
@policy.authorize_wsgi("mogan:node", "get_all",
|
||||||
|
need_target=False)
|
||||||
|
@expose.expose(Nodes)
|
||||||
|
def get_all(self):
|
||||||
|
"""Retrieve a list of nodes."""
|
||||||
|
|
||||||
|
nodes = pecan.request.engine_api.list_compute_nodes(
|
||||||
|
pecan.request.context)
|
||||||
|
|
||||||
|
collection = Nodes()
|
||||||
|
collection.nodes = nodes['nodes']
|
||||||
|
return collection
|
@ -159,6 +159,9 @@ server_policies = [
|
|||||||
policy.RuleDefault('mogan:aggregate:get_one',
|
policy.RuleDefault('mogan:aggregate:get_one',
|
||||||
'rule:admin_api',
|
'rule:admin_api',
|
||||||
description='Show aggregate details'),
|
description='Show aggregate details'),
|
||||||
|
policy.RuleDefault('mogan:node:get_all',
|
||||||
|
'rule:admin_api',
|
||||||
|
description='Get the nodes list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -516,3 +516,7 @@ class API(object):
|
|||||||
def detach_interface(self, context, server, port_id):
|
def detach_interface(self, context, server, port_id):
|
||||||
self.engine_rpcapi.detach_interface(context, server=server,
|
self.engine_rpcapi.detach_interface(context, server=server,
|
||||||
port_id=port_id)
|
port_id=port_id)
|
||||||
|
|
||||||
|
def list_compute_nodes(self, context):
|
||||||
|
"""Get compute node list."""
|
||||||
|
return self.engine_rpcapi.list_compute_nodes(context)
|
||||||
|
@ -580,3 +580,8 @@ class EngineManager(base_manager.BaseEngineManager):
|
|||||||
nic.delete(context)
|
nic.delete(context)
|
||||||
|
|
||||||
LOG.info('Interface was successfully detached')
|
LOG.info('Interface was successfully detached')
|
||||||
|
|
||||||
|
def list_compute_nodes(self, context):
|
||||||
|
nodes = self.scheduler_client.reportclient \
|
||||||
|
.get_nodes_from_resource_providers()
|
||||||
|
return nodes
|
||||||
|
@ -92,3 +92,7 @@ class EngineAPI(object):
|
|||||||
cctxt = self.client.prepare(topic=self.topic, server=CONF.host)
|
cctxt = self.client.prepare(topic=self.topic, server=CONF.host)
|
||||||
cctxt.call(context, 'detach_interface', server=server,
|
cctxt.call(context, 'detach_interface', server=server,
|
||||||
port_id=port_id)
|
port_id=port_id)
|
||||||
|
|
||||||
|
def list_compute_nodes(self, context):
|
||||||
|
cctxt = self.client.prepare(topic=self.topic, server=CONF.host)
|
||||||
|
return cctxt.call(context, 'list_compute_nodes')
|
||||||
|
@ -709,3 +709,8 @@ class SchedulerReportClient(object):
|
|||||||
LOG.info('Deleted allocation for resource provider %s', rp_uuid)
|
LOG.info('Deleted allocation for resource provider %s', rp_uuid)
|
||||||
for consumer_id in allocations:
|
for consumer_id in allocations:
|
||||||
self.delete_allocation_for_server(consumer_id)
|
self.delete_allocation_for_server(consumer_id)
|
||||||
|
|
||||||
|
def get_nodes_from_resource_providers(self):
|
||||||
|
# Use the rps we cached
|
||||||
|
rps = self._resource_providers
|
||||||
|
return {'nodes': [rp['name'] for id, rp in rps.items()]}
|
||||||
|
30
mogan/tests/functional/api/v1/test_nodes.py
Normal file
30
mogan/tests/functional/api/v1/test_nodes.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Copyright 2017 Huawei Technologies Co., Ltd.
|
||||||
|
#
|
||||||
|
# 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 mock
|
||||||
|
|
||||||
|
from mogan.tests.functional.api import v1 as v1_test
|
||||||
|
|
||||||
|
|
||||||
|
class TestNode(v1_test.APITestV1):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestNode, self).setUp()
|
||||||
|
|
||||||
|
@mock.patch('mogan.engine.rpcapi.EngineAPI.list_compute_nodes')
|
||||||
|
def test_node_get_all(self, get_nodes):
|
||||||
|
get_nodes.return_value = {'nodes': ['node-0', 'node-1']}
|
||||||
|
headers = self.gen_headers(self.context, roles="admin")
|
||||||
|
resp = self.get_json('/nodes', headers=headers)
|
||||||
|
self.assertItemsEqual(['node-0', 'node-1'], resp['nodes'])
|
29
mogan/tests/tempest/api/test_nodes.py
Normal file
29
mogan/tests/tempest/api/test_nodes.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Copyright 2017 Huawei Technologies Co., Ltd.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
from mogan.tests.tempest.api import base
|
||||||
|
|
||||||
|
|
||||||
|
class BaremetalComputeAPINodesTest(base.BaseBaremetalComputeTest):
|
||||||
|
@classmethod
|
||||||
|
def resource_setup(cls):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resource_cleanup(cls):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_nodes_list(self):
|
||||||
|
nodes = self.baremetal_compute_client.list_nodes()
|
||||||
|
self.assertIsInstance(nodes, list)
|
||||||
|
self.assertEqual(len(nodes), 1)
|
Loading…
Reference in New Issue
Block a user