Add compute node list API for admin
Admin should be able to list the compute nodes in order to divide them into aggregate groups. Change-Id: I33760d06607d0816c73f806b529d1729c211e793
This commit is contained in:
parent
75bfaeb0f3
commit
23871c345b
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 node information.
|
||||
|
||||
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
|
@ -353,6 +353,12 @@ nics:
|
||||
in: body
|
||||
required: true
|
||||
type: dict
|
||||
nodes:
|
||||
description: |
|
||||
The compute node list information.
|
||||
in: body
|
||||
required: true
|
||||
type: dict
|
||||
personality:
|
||||
description: |
|
||||
The file path and contents, text only, to inject into the server at launch. The
|
||||
|
22
api-ref/source/v1/samples/nodes/node-list-resp.json
Normal file
22
api-ref/source/v1/samples/nodes/node-list-resp.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"nodes" : [
|
||||
{
|
||||
"node_uuid" : "99a0fdb0-d73f-471b-841d-a6e149c4a9a4",
|
||||
"updated_at" : null,
|
||||
"hypervisor_type" : "ironic",
|
||||
"node_type" : "2288V3",
|
||||
"created_at" : "2017-06-02T02:25:14+00:00",
|
||||
"extra_specs" : {},
|
||||
"availability_zone" : null
|
||||
},
|
||||
{
|
||||
"extra_specs" : {},
|
||||
"availability_zone" : null,
|
||||
"node_type" : "2288V3",
|
||||
"hypervisor_type" : "ironic",
|
||||
"node_uuid" : "4f047692-fe12-4706-993e-e1b4e99f016b",
|
||||
"updated_at" : null,
|
||||
"created_at" : "2017-06-02T02:33:22+00:00"
|
||||
}
|
||||
]
|
||||
}
|
@ -28,6 +28,7 @@ from mogan.api.controllers import link
|
||||
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
|
||||
|
||||
@ -50,6 +51,9 @@ class V1(base.APIBase):
|
||||
keypairs = [link.Link]
|
||||
"""Links to the keypairs resource"""
|
||||
|
||||
nodes = [link.Link]
|
||||
"""Links to the nodes resource"""
|
||||
|
||||
@staticmethod
|
||||
def convert():
|
||||
v1 = V1()
|
||||
@ -84,6 +88,14 @@ class V1(base.APIBase):
|
||||
'keypairs', '',
|
||||
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
|
||||
|
||||
|
||||
@ -94,6 +106,7 @@ class Controller(rest.RestController):
|
||||
servers = servers.ServerController()
|
||||
availability_zones = availability_zone.AvailabilityZoneController()
|
||||
keypairs = keypairs.KeyPairController()
|
||||
nodes = nodes.NodeController()
|
||||
|
||||
@expose.expose(V1)
|
||||
def get(self):
|
||||
|
80
mogan/api/controllers/v1/nodes.py
Normal file
80
mogan/api/controllers/v1/nodes.py
Normal file
@ -0,0 +1,80 @@
|
||||
# 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.controllers.v1 import types
|
||||
from mogan.api import expose
|
||||
from mogan.common import policy
|
||||
from mogan import objects
|
||||
|
||||
|
||||
class Node(base.APIBase):
|
||||
"""API representation of a node.
|
||||
|
||||
This class enforces type checking and value constraints, and converts
|
||||
between the internal object model and the API representation of
|
||||
a node.
|
||||
"""
|
||||
node_uuid = types.uuid
|
||||
"""The UUID of the node"""
|
||||
|
||||
availability_zone = wtypes.text
|
||||
"""The availability zone of the node"""
|
||||
|
||||
node_type = wtypes.text
|
||||
"""The type of the node"""
|
||||
|
||||
hypervisor_type = wtypes.text
|
||||
"""The hypervisor type of the node"""
|
||||
|
||||
extra_specs = {wtypes.text: types.jsontype}
|
||||
"""The meta data of the node"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(Node, self).__init__(**kwargs)
|
||||
self.fields = []
|
||||
for field in objects.ComputeNode.fields:
|
||||
# Skip fields we do not expose.
|
||||
if not hasattr(self, field):
|
||||
continue
|
||||
self.fields.append(field)
|
||||
setattr(self, field, kwargs.get(field, wtypes.Unset))
|
||||
|
||||
|
||||
class NodeCollection(base.APIBase):
|
||||
"""API representation of a collection of nodes."""
|
||||
|
||||
nodes = [Node]
|
||||
"""A list containing compute node objects"""
|
||||
|
||||
|
||||
class NodeController(rest.RestController):
|
||||
"""REST controller for Node."""
|
||||
|
||||
@policy.authorize_wsgi("mogan:node", "get_all",
|
||||
need_target=False)
|
||||
@expose.expose(NodeCollection)
|
||||
def get_all(self):
|
||||
"""Retrieve a list of nodes."""
|
||||
|
||||
nodes = objects.ComputeNodeList.get_all_available(
|
||||
pecan.request.context)
|
||||
nodes_data = [Node(**node.as_dict()) for node in nodes]
|
||||
|
||||
return NodeCollection(nodes=nodes_data)
|
@ -150,6 +150,9 @@ server_policies = [
|
||||
policy.RuleDefault('mogan:flavor_extra_specs:get_all',
|
||||
'rule:allow',
|
||||
description='Retrieve flavor extra specs'),
|
||||
policy.RuleDefault('mogan:node:get_all',
|
||||
'rule:admin_api',
|
||||
description='Retrieve all compute nodes'),
|
||||
]
|
||||
|
||||
|
||||
|
26
mogan/tests/functional/api/v1/test_nodes.py
Normal file
26
mogan/tests/functional/api/v1/test_nodes.py
Normal file
@ -0,0 +1,26 @@
|
||||
# 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.functional.api import v1 as v1_test
|
||||
|
||||
|
||||
class TestNode(v1_test.APITestV1):
|
||||
|
||||
def setUp(self):
|
||||
super(TestNode, self).setUp()
|
||||
|
||||
def test_node_get_all(self):
|
||||
headers = self.gen_headers(self.context, roles="admin")
|
||||
resp = self.get_json('/nodes', headers=headers)
|
||||
self.assertItemsEqual([], resp['nodes'])
|
Loading…
Reference in New Issue
Block a user