metal/inventory/inventory/inventory/api/controllers/v1/node.py

262 lines
9.3 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2013 UnitedStack Inc.
# 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.
#
# Copyright (c) 2013-2016 Wind River Systems, Inc.
#
import six
import pecan
from pecan import rest
from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from inventory.api.controllers.v1 import base
from inventory.api.controllers.v1 import collection
from inventory.api.controllers.v1 import cpu
from inventory.api.controllers.v1 import link
from inventory.api.controllers.v1 import memory
from inventory.api.controllers.v1 import port
from inventory.api.controllers.v1 import types
from inventory.api.controllers.v1 import utils
from inventory.common import exception
from inventory.common.i18n import _
from inventory import objects
from oslo_log import log
LOG = log.getLogger(__name__)
class NodePatchType(types.JsonPatchType):
@staticmethod
def mandatory_attrs():
return ['/address', '/host_uuid']
class Node(base.APIBase):
"""API representation of a host node.
This class enforces type checking and value constraints, and converts
between the internal object model and the API representation of
an node.
"""
uuid = types.uuid
"Unique UUID for this node"
numa_node = int
"numa node zone for this node"
capabilities = {wtypes.text: utils.ValidTypes(wtypes.text,
six.integer_types)}
"This node's meta data"
host_id = int
"The hostid that this node belongs to"
host_uuid = types.uuid
"The UUID of the host this node belongs to"
links = [link.Link]
"A list containing a self link and associated node links"
icpus = [link.Link]
"Links to the collection of cpus on this node"
imemorys = [link.Link]
"Links to the collection of memorys on this node"
ports = [link.Link]
"Links to the collection of ports on this node"
def __init__(self, **kwargs):
self.fields = objects.Node.fields.keys()
for k in self.fields:
setattr(self, k, kwargs.get(k))
@classmethod
def convert_with_links(cls, rpc_node, expand=True):
minimum_fields = ['uuid', 'numa_node', 'capabilities',
'host_uuid', 'host_id',
'created_at'] if not expand else None
fields = minimum_fields if not expand else None
node = Node.from_rpc_object(rpc_node, fields)
# never expose the host_id attribute
node.host_id = wtypes.Unset
node.links = [link.Link.make_link('self', pecan.request.host_url,
'nodes', node.uuid),
link.Link.make_link('bookmark',
pecan.request.host_url,
'nodes', node.uuid,
bookmark=True)
]
if expand:
node.icpus = [link.Link.make_link('self',
pecan.request.host_url,
'nodes',
node.uuid + "/cpus"),
link.Link.make_link('bookmark',
pecan.request.host_url,
'nodes',
node.uuid + "/cpus",
bookmark=True)
]
node.imemorys = [link.Link.make_link('self',
pecan.request.host_url,
'nodes',
node.uuid + "/memorys"),
link.Link.make_link('bookmark',
pecan.request.host_url,
'nodes',
node.uuid + "/memorys",
bookmark=True)
]
node.ports = [link.Link.make_link('self',
pecan.request.host_url,
'nodes',
node.uuid + "/ports"),
link.Link.make_link('bookmark',
pecan.request.host_url,
'nodes',
node.uuid + "/ports",
bookmark=True)
]
return node
class NodeCollection(collection.Collection):
"""API representation of a collection of nodes."""
nodes = [Node]
"A list containing node objects"
def __init__(self, **kwargs):
self._type = 'nodes'
@classmethod
def convert_with_links(cls, rpc_nodes, limit, url=None,
expand=False, **kwargs):
collection = NodeCollection()
collection.nodes = [Node.convert_with_links(p, expand)
for p in rpc_nodes]
collection.next = collection.get_next(limit, url=url, **kwargs)
return collection
LOCK_NAME = 'NodeController'
class NodeController(rest.RestController):
"""REST controller for nodes."""
icpus = cpu.CPUController(from_node=True)
"Expose cpus as a sub-element of nodes"
imemorys = memory.MemoryController(from_node=True)
"Expose memorys as a sub-element of nodes"
ports = port.PortController(from_node=True)
"Expose ports as a sub-element of nodes"
_custom_actions = {
'detail': ['GET'],
}
def __init__(self, from_hosts=False):
self._from_hosts = from_hosts
def _get_nodes_collection(self, host_uuid, marker, limit, sort_key,
sort_dir, expand=False, resource_url=None):
if self._from_hosts and not host_uuid:
raise exception.InvalidParameterValue(_(
"Host id not specified."))
limit = utils.validate_limit(limit)
sort_dir = utils.validate_sort_dir(sort_dir)
marker_obj = None
if marker:
marker_obj = objects.Node.get_by_uuid(pecan.request.context,
marker)
if host_uuid:
nodes = objects.Node.get_by_host(pecan.request.context,
host_uuid,
limit,
marker=marker_obj,
sort_key=sort_key,
sort_dir=sort_dir)
else:
nodes = objects.Node.list(pecan.request.context,
limit,
marker=marker_obj,
sort_key=sort_key,
sort_dir=sort_dir)
return NodeCollection.convert_with_links(nodes, limit,
url=resource_url,
expand=expand,
sort_key=sort_key,
sort_dir=sort_dir)
@wsme_pecan.wsexpose(NodeCollection,
types.uuid, types.uuid, int, wtypes.text, wtypes.text)
def get_all(self, host_uuid=None, marker=None, limit=None,
sort_key='id', sort_dir='asc'):
"""Retrieve a list of nodes."""
return self._get_nodes_collection(host_uuid, marker, limit,
sort_key, sort_dir)
@wsme_pecan.wsexpose(NodeCollection, types.uuid, types.uuid, int,
wtypes.text, wtypes.text)
def detail(self, host_uuid=None, marker=None, limit=None,
sort_key='id', sort_dir='asc'):
"""Retrieve a list of nodes with detail."""
# NOTE(lucasagomes): /detail should only work agaist collections
parent = pecan.request.path.split('/')[:-1][-1]
if parent != "nodes":
raise exception.HTTPNotFound
expand = True
resource_url = '/'.join(['nodes', 'detail'])
return self._get_nodes_collection(host_uuid,
marker, limit,
sort_key, sort_dir,
expand, resource_url)
@wsme_pecan.wsexpose(Node, types.uuid)
def get_one(self, node_uuid):
"""Retrieve information about the given node."""
if self._from_hosts:
raise exception.OperationNotPermitted
rpc_node = objects.Node.get_by_uuid(pecan.request.context, node_uuid)
return Node.convert_with_links(rpc_node)