nfv/nfv/nfv-vim/nfv_vim/api/controllers/v1/virtualised_resources/_image_api.py

410 lines
17 KiB
Python
Executable File

#
# Copyright (c) 2015-2016 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from six.moves import http_client as httplib
import json
import pecan
from pecan import rest
from wsme import types as wsme_types
import wsmeext.pecan as wsme_pecan
from nfv_common import debug
from nfv_common import validate
from nfv_vim import rpc
DLOG = debug.debug_get_logger('nfv_vim.api.image')
# The following container-format types are supported:
# ami - Amazon Machine Image
# ari - Amazon RAM Disk
# aki - Amazon Kernel Image
# bare - No Container
# ovf - Open Virtualization Format
# ova - Open Virtual Application
ContainerFormatType = wsme_types.Enum(str, 'ami', 'ari', 'aki', 'bare',
'ovf', 'ova')
# The following disk-format types are supported:
# ami - Amazon Machine Image
# ari - Amazon RAM Disk
# aki - Amazon Kernel Image
# vhd - Virtual Hard Disk
# vmdk - Virtual Machine Disk
# raw - Unstructured Disk Image
# qcow2 - QEMU Emulator supported file that supports Copy-On-Write
# vdi - Virtual Disk image
# iso - Archive Format ISO-9660, UDF standards
DiskFormatType = wsme_types.Enum(str, 'ami', 'ari', 'aki', 'vhd', 'vmdk',
'raw', 'qcow2', 'vdi', 'iso')
# The following visibility types are supported:
# private - private to the owner
# public - image is available to all users
# shared - image is shared
VisibilityType = wsme_types.Enum(str, 'private', 'public', 'shared')
class ImageCreateData(wsme_types.Base):
"""
Image - Create Data
"""
name = wsme_types.wsattr(unicode, mandatory=True)
description = wsme_types.wsattr(unicode, mandatory=False, default="")
container_format = wsme_types.wsattr(ContainerFormatType, mandatory=True)
disk_format = wsme_types.wsattr(DiskFormatType, mandatory=True)
minimum_disk_size = wsme_types.wsattr(int, mandatory=False, default=0)
minimum_memory_size = wsme_types.wsattr(int, mandatory=False, default=0)
visibility = wsme_types.wsattr(VisibilityType, mandatory=False,
default="public")
protected = wsme_types.wsattr(bool, mandatory=False, default=False)
properties = wsme_types.wsattr(unicode, mandatory=False, default=None)
image_data_ref = wsme_types.wsattr(unicode, mandatory=True)
def __str__(self):
return ("name=%s, description=%s, container_format=%s, "
"disk_format=%s, minimum_disk_size=%s, "
"minimum_memory_size=%s, visibility=%s, protected=%s, "
"properties=%s, image_data_ref=%s"
% (self.name, self.description, self.container_format,
self.disk_format, self.minimum_disk_size,
self.minimum_memory_size, self.visibility, self.protected,
self.properties, self.image_data_ref))
class ImageUpdateData(wsme_types.Base):
"""
Image - Update Data
"""
description = wsme_types.wsattr(unicode, mandatory=False, default=None)
minimum_disk_size = wsme_types.wsattr(int, mandatory=False, default=None)
minimum_memory_size = wsme_types.wsattr(int, mandatory=False, default=None)
visibility = wsme_types.wsattr(VisibilityType, mandatory=False,
default=None)
protected = wsme_types.wsattr(bool, mandatory=False, default=None)
properties = wsme_types.wsattr(unicode, mandatory=False, default=None)
class ImageQueryData(wsme_types.Base):
"""
Image - Query Data
"""
uuid = unicode
name = unicode
description = unicode
container_format = ContainerFormatType
disk_format = DiskFormatType
minimum_disk_size = int
minimum_memory_size = int
visibility = VisibilityType
protected = unicode
availability_status = [unicode]
action = unicode
properties = unicode
def __json__(self):
json_data = dict()
json_data['uuid'] = self.uuid
json_data['name'] = self.name
json_data['description'] = self.description
json_data['container_format'] = self.container_format
json_data['disk_format'] = self.disk_format
json_data['minimum_disk_size'] = self.minimum_disk_size
json_data['minimum_memory_size'] = self.minimum_memory_size
json_data['visibility'] = self.visibility
json_data['protected'] = self.protected
json_data['availability_status'] = json.dumps(self.availability_status)
json_data['action'] = self.action
json_data['properties'] = json.dumps(self.properties)
return json_data
class ImageAPI(rest.RestController):
"""
Image Rest API
"""
@staticmethod
def _get_image_details(image_uuid, image):
"""
Return image details
"""
vim_connection = pecan.request.vim.open_connection()
rpc_request = rpc.APIRequestGetImage()
rpc_request.filter_by_uuid = image_uuid
vim_connection.send(rpc_request.serialize())
msg = vim_connection.receive()
if msg is None:
DLOG.error("No response received for image %s." % image_uuid)
return httplib.INTERNAL_SERVER_ERROR
response = rpc.RPCMessage.deserialize(msg)
if rpc.RPC_MSG_TYPE.GET_IMAGE_RESPONSE != response.type:
DLOG.error("Unexpected message type received, msg_type=%s."
% response.type)
return httplib.INTERNAL_SERVER_ERROR
if rpc.RPC_MSG_RESULT.NOT_FOUND == response.result:
DLOG.debug("Image %s was not found." % image_uuid)
return httplib.NOT_FOUND
elif rpc.RPC_MSG_RESULT.SUCCESS == response.result:
image.uuid = response.uuid
image.name = response.name
image.description = response.description
image.container_format = response.container_format
image.disk_format = response.disk_format
image.minimum_disk_size = response.min_disk_size_gb
image.minimum_memory_size = response.min_memory_size_mb
image.visibility = response.visibility
image.protected = response.protected
image.availability_status = response.avail_status
image.action = response.action
image.properties = response.properties
return httplib.OK
DLOG.error("Unexpected result received for image %s, result=%s."
% (image_uuid, response.result))
return httplib.INTERNAL_SERVER_ERROR
@wsme_pecan.wsexpose(ImageQueryData, unicode, status_code=httplib.OK)
def get_one(self, image_uuid):
DLOG.verbose("Image-API get called for image %s." % image_uuid)
if not validate.valid_uuid_str(image_uuid):
DLOG.error("Invalid uuid received, uuid=%s." % image_uuid)
return pecan.abort(httplib.BAD_REQUEST)
image = ImageQueryData()
http_response = self._get_image_details(image_uuid, image)
if httplib.OK == http_response:
return image
else:
return pecan.abort(http_response)
@wsme_pecan.wsexpose([ImageQueryData], status_code=httplib.OK)
def get_all(self):
DLOG.verbose("Image-API get-all called.")
vim_connection = pecan.request.vim.open_connection()
rpc_request = rpc.APIRequestGetImage()
rpc_request.get_all = True
vim_connection.send(rpc_request.serialize())
images = list()
while True:
msg = vim_connection.receive()
if msg is None:
DLOG.verbose("Done receiving.")
break
response = rpc.RPCMessage.deserialize(msg)
if rpc .RPC_MSG_TYPE.GET_IMAGE_RESPONSE != response.type:
DLOG.error("Unexpected message type received, msg_type=%s."
% response.type)
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
if rpc.RPC_MSG_RESULT.SUCCESS != response.result:
DLOG.error("Unexpected result received, result=%s."
% response.result)
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
DLOG.verbose("Received response=%s." % response)
image = ImageQueryData()
image.uuid = response.uuid
image.name = response.name
image.description = response.description
image.container_format = response.container_format
image.disk_format = response.disk_format
image.minimum_disk_size = response.min_disk_size_gb
image.minimum_memory_size = response.min_memory_size_mb
image.visibility = response.visibility
image.protected = response.protected
image.availability_status = response.avail_status
image.action = response.action
image.properties = response.properties
images.append(image)
return images
@wsme_pecan.wsexpose(ImageQueryData, body=ImageCreateData,
status_code=httplib.CREATED)
def post(self, image_create_data):
DLOG.verbose("Image-API create called for image %s, request=%s."
% (image_create_data.name, image_create_data))
if image_create_data.properties is not None:
try:
properties = json.loads(image_create_data.properties)
except ValueError:
DLOG.error("Invalid properties received, properties=%s."
% image_create_data.properties)
return pecan.abort(httplib.BAD_REQUEST)
else:
properties = None
vim_connection = pecan.request.vim.open_connection()
rpc_request = rpc.APIRequestCreateImage()
rpc_request.name = image_create_data.name
rpc_request.description = image_create_data.description
rpc_request.container_format = image_create_data.container_format
rpc_request.disk_format = image_create_data.disk_format
rpc_request.min_disk_size_gb = image_create_data.minimum_disk_size
rpc_request.min_memory_size_mb = image_create_data.minimum_memory_size
rpc_request.visibility = image_create_data.visibility
rpc_request.protected = image_create_data.protected
rpc_request.properties = properties
rpc_request.image_data_ref = image_create_data.image_data_ref
vim_connection.send(rpc_request.serialize())
msg = vim_connection.receive(timeout_in_secs=180)
if msg is None:
DLOG.error("No response received for image %s."
% image_create_data.name)
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
response = rpc.RPCMessage.deserialize(msg)
if rpc.RPC_MSG_TYPE.CREATE_IMAGE_RESPONSE != response.type:
DLOG.error("Unexpected message type received, msg_type=%s."
% response.type)
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
if rpc.RPC_MSG_RESULT.SUCCESS == response.result:
image = ImageQueryData()
image.uuid = response.uuid
image.name = response.name
image.description = response.description
image.container_format = response.container_format
image.disk_format = response.disk_format
image.minimum_disk_size = response.min_disk_size_gb
image.minimum_memory_size = response.min_memory_size_mb
image.visibility = response.visibility
image.protected = response.protected
image.availability_status = response.avail_status
image.action = response.action
image.properties = response.properties
return image
DLOG.error("Unexpected result received for image %s, result=%s."
% (image_create_data.name, response.result))
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
@wsme_pecan.wsexpose(ImageQueryData, unicode, body=ImageUpdateData,
status_code=httplib.OK)
def put(self, image_uuid, image_update_data):
DLOG.verbose("Image-API update called for image %s." % image_uuid)
if not validate.valid_uuid_str(image_uuid):
DLOG.error("Invalid uuid received, uuid=%s." % image_uuid)
return pecan.abort(httplib.BAD_REQUEST)
image_data = ImageQueryData()
http_response = self._get_image_details(image_uuid, image_data)
if httplib.OK != http_response:
return pecan.abort(http_response)
rpc_request = rpc.APIRequestUpdateImage()
rpc_request.uuid = image_uuid
if image_update_data.description is None:
rpc_request.description = image_data.description
else:
rpc_request.description = image_update_data.description
if image_update_data.minimum_disk_size is None:
rpc_request.min_disk_size_gb = image_data.minimum_disk_size
else:
rpc_request.min_disk_size_gb = image_update_data.minimum_disk_size
if image_update_data.minimum_memory_size is None:
rpc_request.min_memory_size_mb = image_data.minimum_memory_size
else:
rpc_request.min_memory_size_mb \
= image_update_data.minimum_memory_size
if image_update_data.visibility is None:
rpc_request.visibility = image_data.visibility
else:
rpc_request.visibility = image_update_data.visibility
if image_update_data.protected is None:
rpc_request.protected = image_data.protected
else:
rpc_request.protected = image_update_data.protected
if image_update_data.properties is None:
rpc_request.properties = json.loads(image_data.properties)
else:
try:
rpc_request.properties \
= json.loads(image_update_data.properties)
except ValueError:
DLOG.error("Invalid properties received, properties=%s."
% image_update_data.properties)
return pecan.abort(httplib.BAD_REQUEST)
vim_connection = pecan.request.vim.open_connection()
vim_connection.send(rpc_request.serialize())
msg = vim_connection.receive()
if msg is None:
DLOG.error("No response received for image %s." % image_uuid)
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
response = rpc.RPCMessage.deserialize(msg)
if rpc.RPC_MSG_TYPE.UPDATE_IMAGE_RESPONSE != response.type:
DLOG.error("Unexpected message type received, msg_type=%s."
% response.type)
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
if rpc.RPC_MSG_RESULT.SUCCESS == response.result:
image = ImageQueryData()
image.uuid = response.uuid
image.name = response.name
image.description = response.description
image.container_format = response.container_format
image.disk_format = response.disk_format
image.minimum_disk_size = response.min_disk_size_gb
image.minimum_memory_size = response.min_memory_size_mb
image.visibility = response.visibility
image.protected = response.protected
image.availability_status = response.avail_status
image.action = response.action
image.properties = response.properties
return image
DLOG.error("Unexpected result received for image %s, result=%s."
% (image_uuid, response.result))
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
@wsme_pecan.wsexpose(None, unicode, status_code=httplib.NO_CONTENT)
def delete(self, image_uuid):
DLOG.verbose("Image-API delete called for image %s." % image_uuid)
if not validate.valid_uuid_str(image_uuid):
DLOG.error("Invalid uuid received, uuid=%s." % image_uuid)
return pecan.abort(httplib.BAD_REQUEST)
vim_connection = pecan.request.vim.open_connection()
rpc_request = rpc.APIRequestDeleteImage()
rpc_request.uuid = image_uuid
vim_connection.send(rpc_request.serialize())
msg = vim_connection.receive()
if msg is None:
DLOG.error("No response received for image %s." % image_uuid)
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
response = rpc.RPCMessage.deserialize(msg)
if rpc.RPC_MSG_TYPE.DELETE_IMAGE_RESPONSE != response.type:
DLOG.error("Unexpected message type received, msg_type=%s."
% response.type)
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
if rpc.RPC_MSG_RESULT.NOT_FOUND == response.result:
DLOG.debug("Image %s was not found." % image_uuid)
return pecan.abort(httplib.NOT_FOUND)
elif rpc.RPC_MSG_RESULT.SUCCESS == response.result:
return None
DLOG.error("Unexpected result received for image %s, result=%s."
% (image_uuid, response.result))
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)