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:
Zhenguo Niu 2017-07-21 15:05:46 +08:00
parent 9627106519
commit 8a8dc20660
12 changed files with 184 additions and 0 deletions

View 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

View File

@ -435,6 +435,12 @@ nics:
in: body
required: true
type: dict
nodes:
description: |
The compute node name list.
in: body
required: true
type: dict
personality:
description: |
The file path and contents, text only, to inject into the server at launch. The

View File

@ -0,0 +1,7 @@
{
"nodes" : [
"node-0",
"node-1",
"node-2"
]
}

View File

@ -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 flavors
from mogan.api.controllers.v1 import keypairs
from mogan.api.controllers.v1 import nodes
from mogan.api.controllers.v1 import servers
from mogan.api import expose
@ -54,6 +55,9 @@ class V1(base.APIBase):
aggregates = [link.Link]
"""Links to the aggregates resource"""
nodes = [link.Link]
"""Links to the nodes resource"""
@staticmethod
def convert():
v1 = V1()
@ -96,6 +100,14 @@ class V1(base.APIBase):
'aggregates', '',
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
@ -107,6 +119,7 @@ class Controller(rest.RestController):
availability_zones = availability_zone.AvailabilityZoneController()
keypairs = keypairs.KeyPairController()
aggregates = aggregates.AggregateController()
nodes = nodes.NodeController()
@expose.expose(V1)
def get(self):

View 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

View File

@ -159,6 +159,9 @@ server_policies = [
policy.RuleDefault('mogan:aggregate:get_one',
'rule:admin_api',
description='Show aggregate details'),
policy.RuleDefault('mogan:node:get_all',
'rule:admin_api',
description='Get the nodes list'),
]

View File

@ -516,3 +516,7 @@ class API(object):
def detach_interface(self, context, server, port_id):
self.engine_rpcapi.detach_interface(context, server=server,
port_id=port_id)
def list_compute_nodes(self, context):
"""Get compute node list."""
return self.engine_rpcapi.list_compute_nodes(context)

View File

@ -580,3 +580,8 @@ class EngineManager(base_manager.BaseEngineManager):
nic.delete(context)
LOG.info('Interface was successfully detached')
def list_compute_nodes(self, context):
nodes = self.scheduler_client.reportclient \
.get_nodes_from_resource_providers()
return nodes

View File

@ -92,3 +92,7 @@ class EngineAPI(object):
cctxt = self.client.prepare(topic=self.topic, server=CONF.host)
cctxt.call(context, 'detach_interface', server=server,
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')

View File

@ -709,3 +709,8 @@ class SchedulerReportClient(object):
LOG.info('Deleted allocation for resource provider %s', rp_uuid)
for consumer_id in allocations:
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()]}

View 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'])

View 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)