Files
mogan/nimble/api/controllers/v1/instances.py
Zhenguo Niu 4aae1d1788 Don't expose instance id to users
Instance id is a internal attribute, should not be exposed
to users.

Change-Id: I406c0b3558fb13fe46636b5d907bbd4c363e5322
2016-09-30 01:21:54 +08:00

240 lines
8.1 KiB
Python

# Copyright 2016 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 jsonschema
import pecan
from pecan import rest
from six.moves import http_client
import wsme
from wsme import types as wtypes
from nimble.api.controllers import base
from nimble.api.controllers import link
from nimble.api.controllers.v1 import types
from nimble.api import expose
from nimble.common import exception
from nimble.common.i18n import _
from nimble import objects
_CREATE_INSTANCE_SCHEMA = {
"$schema": "http://json-schema.org/schema#",
"title": "Create instance schema",
"type": "object",
"properties": {
'name': {'type': 'string', 'minLength': 1, 'maxLength': 255},
'description': {'type': 'string', 'minLength': 1, 'maxLength': 255},
'availability_zone': {'type': 'string', 'minLength': 1,
'maxLength': 255},
'image_uuid': {'type': 'string', 'format': 'uuid'},
'instance_type_uuid': {'type': 'string', 'format': 'uuid'},
'networks': {
'type': 'array', 'minItems': 1,
'items': {
'type': 'object',
'properties': {
'uuid': {'type': 'string', 'format': 'uuid'},
'port_type': {'type': 'string', 'minLength': 1,
'maxLength': 255},
},
'required': ['uuid'],
'additionalProperties': False,
},
},
},
'required': ['name', 'image_uuid', 'instance_type_uuid', 'networks'],
'additionalProperties': False,
}
class Instance(base.APIBase):
"""API representation of a instance.
This class enforces type checking and value constraints, and converts
between the internal object model and the API representation of
a instance.
"""
uuid = types.uuid
"""The UUID of the instance"""
name = wtypes.text
"""The name of the instance"""
description = wtypes.text
"""The description of the instance"""
project_id = types.uuid
"""The project UUID of the instance"""
user_id = types.uuid
"""The user UUID of the instance"""
status = wtypes.text
"""The status of the instance"""
power_state = wtypes.text
"""The power state of the instance"""
task_state = wtypes.text
"""The task state of the instance"""
availability_zone = wtypes.text
"""The availability zone of the instance"""
instance_type_uuid = types.uuid
"""The instance type UUID of the instance"""
image_uuid = types.uuid
"""The image UUID of the instance"""
network_info = {wtypes.text: types.jsontype}
"""The network information of the instance"""
links = wsme.wsattr([link.Link], readonly=True)
"""A list containing a self link"""
def __init__(self, **kwargs):
self.fields = []
for field in objects.Instance.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))
@classmethod
def convert_with_links(cls, rpc_instance):
instance = Instance(**rpc_instance.as_dict())
url = pecan.request.public_url
instance.links = [link.Link.make_link('self',
url,
'instances', instance.uuid),
link.Link.make_link('bookmark',
url,
'instances', instance.uuid,
bookmark=True)
]
return instance
class InstanceCollection(base.APIBase):
"""API representation of a collection of instance."""
instances = [Instance]
"""A list containing instance objects"""
@staticmethod
def convert_with_links(instances, url=None, **kwargs):
collection = InstanceCollection()
collection.instances = [Instance.convert_with_links(inst)
for inst in instances]
return collection
class InstanceActionController(rest.RestController):
_custom_actions = {
'power': ['PUT'],
}
class InstanceController(rest.RestController):
"""REST controller for Instance."""
action = InstanceActionController()
@expose.expose(InstanceCollection)
def get_all(self):
"""Retrieve a list of instance."""
instances = objects.Instance.list(pecan.request.context)
return InstanceCollection.convert_with_links(instances)
@expose.expose(Instance, types.uuid)
def get_one(self, instance_uuid):
"""Retrieve information about the given instance.
:param instance_uuid: UUID of a instance.
"""
rpc_instance = objects.Instance.get(pecan.request.context,
instance_uuid)
return Instance.convert_with_links(rpc_instance)
@expose.expose(Instance, body=types.jsontype,
status_code=http_client.CREATED)
def post(self, instance):
"""Create a new instance.
:param instance: a instance within the request body.
"""
# Add jsonschema validate
_check_create_body(instance)
requested_networks = instance.pop('networks', None)
instance_type_uuid = instance.get('instance_type_uuid')
try:
instance_type = objects.InstanceType.get(pecan.request.context,
instance_type_uuid)
except exception.InstanceTypeNotFound:
msg = (_("InstanceType %s could not be found") %
instance_type_uuid)
raise wsme.exc.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)
instance_obj = objects.Instance(pecan.request.context, **instance)
instance_obj.create()
instance_obj.user_id = pecan.request.context.user_id
instance_obj.project_id = pecan.request.context.project_id
instance_obj.save()
# TODO(zhenguo): Catch exceptions
pecan.request.rpcapi.create_instance(pecan.request.context,
instance_obj,
requested_networks,
instance_type)
# Set the HTTP Location Header
pecan.response.location = link.build_url('instance', instance_obj.uuid)
return Instance.convert_with_links(instance_obj)
@expose.expose(None, types.uuid, status_code=http_client.NO_CONTENT)
def delete(self, instance_uuid):
"""Delete a instance.
:param instance_uuid: UUID of a instance.
"""
rpc_instance = objects.Instance.get(pecan.request.context,
instance_uuid)
pecan.request.rpcapi.delete_instance(pecan.request.context,
rpc_instance)
def _check_create_body(body):
"""Ensure all necessary keys are present and correct in create body.
Check that the user-specified create body is in the expected format and
include the required information.
:param body: create instance body
:raises: InvalidParameterValue if validation of create body fails.
"""
try:
jsonschema.validate(body, _CREATE_INSTANCE_SCHEMA)
except jsonschema.ValidationError as exc:
raise exception.InvalidParameterValue(_('Invalid create body: %s') %
exc)