208 lines
8.0 KiB
Python
208 lines
8.0 KiB
Python
from pecan import rest
|
|
from iotronic.api import expose
|
|
from wsme import types as wtypes
|
|
from iotronic import objects
|
|
from iotronic.api.controllers.v1 import types
|
|
from iotronic.api.controllers.v1 import collection
|
|
from iotronic.api.controllers.v1 import utils as api_utils
|
|
from iotronic.api.controllers import base
|
|
from oslo_utils import uuidutils
|
|
import wsme
|
|
import pecan
|
|
from pecan import rest
|
|
|
|
|
|
class Node(base.APIBase):
|
|
"""API representation of a node.
|
|
"""
|
|
|
|
uuid = types.uuid
|
|
code = wsme.wsattr(wtypes.text)
|
|
status = wsme.wsattr(wtypes.text)
|
|
|
|
@staticmethod
|
|
def _convert_with_links(node, url, expand=True, show_password=True):
|
|
'''
|
|
if not expand:
|
|
except_list = ['instance_uuid', 'maintenance', 'power_state',
|
|
'provision_state', 'uuid', 'name']
|
|
node.unset_fields_except(except_list)
|
|
else:
|
|
if not show_password:
|
|
node.driver_info = ast.literal_eval(strutils.mask_password(
|
|
node.driver_info,
|
|
"******"))
|
|
node.ports = [link.Link.make_link('self', url, 'nodes',
|
|
node.uuid + "/ports"),
|
|
link.Link.make_link('bookmark', url, 'nodes',
|
|
node.uuid + "/ports",
|
|
bookmark=True)
|
|
]
|
|
|
|
node.chassis_id = wtypes.Unset
|
|
'''
|
|
'''
|
|
node.links = [link.Link.make_link('self', url, 'nodes',
|
|
node.uuid),
|
|
link.Link.make_link('bookmark', url, 'nodes',
|
|
node.uuid, bookmark=True)
|
|
]
|
|
'''
|
|
return node
|
|
|
|
@classmethod
|
|
def convert_with_links(cls, rpc_node, expand=True):
|
|
node = Node(**rpc_node.as_dict())
|
|
return cls._convert_with_links(node, pecan.request.host_url,
|
|
expand,
|
|
pecan.request.context.show_password)
|
|
|
|
def __init__(self, **kwargs):
|
|
self.fields = []
|
|
fields = list(objects.Node.fields)
|
|
for k in fields:
|
|
# Skip fields we do not expose.
|
|
if not hasattr(self, k):
|
|
continue
|
|
self.fields.append(k)
|
|
setattr(self, k, kwargs.get(k, wtypes.Unset))
|
|
|
|
class NodeCollection(collection.Collection):
|
|
"""API representation of a collection of nodes."""
|
|
|
|
nodes = [Node]
|
|
"""A list containing nodes objects"""
|
|
|
|
def __init__(self, **kwargs):
|
|
self._type = 'nodes'
|
|
|
|
@staticmethod
|
|
def convert_with_links(nodes, limit, url=None, expand=False, **kwargs):
|
|
collection = NodeCollection()
|
|
collection.nodes = [Node.convert_with_links(n, expand) for n in nodes]
|
|
collection.next = collection.get_next(limit, url=url, **kwargs)
|
|
return collection
|
|
|
|
class NodesController(rest.RestController):
|
|
|
|
invalid_sort_key_list = ['properties']
|
|
|
|
def _get_nodes_collection(self, chassis_uuid, instance_uuid, associated,
|
|
maintenance, marker, limit, sort_key, sort_dir,
|
|
expand=False, resource_url=None):
|
|
'''
|
|
if self.from_chassis and not chassis_uuid:
|
|
raise exception.MissingParameterValue(
|
|
_("Chassis id not specified."))
|
|
'''
|
|
limit = api_utils.validate_limit(limit)
|
|
sort_dir = api_utils.validate_sort_dir(sort_dir)
|
|
|
|
marker_obj = None
|
|
if marker:
|
|
marker_obj = objects.Node.get_by_uuid(pecan.request.context,
|
|
marker)
|
|
|
|
if sort_key in self.invalid_sort_key_list:
|
|
raise exception.InvalidParameterValue(
|
|
_("The sort_key value %(key)s is an invalid field for "
|
|
"sorting") % {'key': sort_key})
|
|
|
|
if instance_uuid:
|
|
nodes = self._get_nodes_by_instance(instance_uuid)
|
|
else:
|
|
filters = {}
|
|
if chassis_uuid:
|
|
filters['chassis_uuid'] = chassis_uuid
|
|
if associated is not None:
|
|
filters['associated'] = associated
|
|
if maintenance is not None:
|
|
filters['maintenance'] = maintenance
|
|
|
|
nodes = objects.Node.list(pecan.request.context, limit, marker_obj,
|
|
sort_key=sort_key, sort_dir=sort_dir,
|
|
filters=filters)
|
|
|
|
parameters = {'sort_key': sort_key, 'sort_dir': sort_dir}
|
|
if associated:
|
|
parameters['associated'] = associated
|
|
if maintenance:
|
|
parameters['maintenance'] = maintenance
|
|
return NodeCollection.convert_with_links(nodes, limit,
|
|
url=resource_url,
|
|
expand=expand,
|
|
**parameters)
|
|
|
|
@expose.expose(NodeCollection, types.uuid, types.uuid, types.boolean,
|
|
types.boolean, types.uuid, int, wtypes.text, wtypes.text)
|
|
def get_all(self, chassis_uuid=None, instance_uuid=None, associated=None,
|
|
maintenance=None, marker=None, limit=None, sort_key='id',
|
|
sort_dir='asc'):
|
|
"""Retrieve a list of nodes.
|
|
|
|
:param chassis_uuid: Optional UUID of a chassis, to get only nodes for
|
|
that chassis.
|
|
:param instance_uuid: Optional UUID of an instance, to find the node
|
|
associated with that instance.
|
|
:param associated: Optional boolean whether to return a list of
|
|
associated or unassociated nodes. May be combined
|
|
with other parameters.
|
|
:param maintenance: Optional boolean value that indicates whether
|
|
to get nodes in maintenance mode ("True"), or not
|
|
in maintenance mode ("False").
|
|
:param marker: pagination marker for large data sets.
|
|
:param limit: maximum number of resources to return in a single result.
|
|
:param sort_key: column to sort results by. Default: id.
|
|
:param sort_dir: direction to sort. "asc" or "desc". Default: asc.
|
|
"""
|
|
return self._get_nodes_collection(chassis_uuid, instance_uuid,
|
|
associated, maintenance, marker,
|
|
limit, sort_key, sort_dir)
|
|
|
|
|
|
|
|
@expose.expose(Node,types.uuid_or_name)
|
|
def get(self,node_ident):
|
|
"""Retrieve information about the given node.
|
|
|
|
:param node_ident: UUID or logical name of a node.
|
|
"""
|
|
rpc_node = api_utils.get_rpc_node(node_ident)
|
|
node = Node(**rpc_node.as_dict())
|
|
return node
|
|
|
|
@expose.expose(None, types.uuid_or_name, status_code=204)
|
|
def delete(self, node_ident):
|
|
"""Delete a node.
|
|
|
|
:param node_ident: UUID or logical name of a node.
|
|
"""
|
|
rpc_node = api_utils.get_rpc_node(node_ident)
|
|
|
|
try:
|
|
topic = pecan.request.rpcapi.get_topic_for(rpc_node)
|
|
except exception.NoValidHost as e:
|
|
e.code = 400
|
|
raise e
|
|
|
|
pecan.request.rpcapi.destroy_node(pecan.request.context,
|
|
rpc_node.uuid, topic)
|
|
|
|
@expose.expose(Node, body=Node, status_code=201)
|
|
def post(self,Node):
|
|
"""Create a new Node.
|
|
|
|
:param Node: a Node within the request body.
|
|
"""
|
|
|
|
if not Node.uuid:
|
|
Node.uuid = uuidutils.generate_uuid()
|
|
if not Node.status:
|
|
Node.status = 'DISCONNECTED'
|
|
new_Node = objects.Node(pecan.request.context,
|
|
**Node.as_dict())
|
|
new_Node.create()
|
|
#pecan.response.location = link.build_url('Nodes', new_Node.uuid)
|
|
return Node.convert_with_links(new_Node)
|
|
|