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

588 lines
23 KiB
Python
Executable File

# Copyright (c) 2015-2016 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import json
import pecan
import six
from six.moves import http_client as httplib
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.virtualised_compute')
ComputeOperationType = wsme_types.Enum(str, 'start', 'stop', 'pause',
'unpause', 'suspend', 'resume',
'reboot')
class ComputeOperateRequestData(wsme_types.Base):
"""
Virtualised Resources - Compute Operate Request Data
"""
compute_operation = wsme_types.wsattr(ComputeOperationType, mandatory=True)
compute_operation_data = wsme_types.wsattr(six.text_type, mandatory=False,
default=None)
class ComputeOperateAPI(pecan.rest.RestController):
"""
Virtualised Resources - Computes Operate API
"""
@staticmethod
def _do_operation(rpc_request):
"""
Return an image details
"""
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 %s." % rpc_request)
return httplib.INTERNAL_SERVER_ERROR
response = rpc.RPCMessage.deserialize(msg)
if rpc.RPC_MSG_RESULT.NOT_FOUND == response.result:
DLOG.debug("Resource was not found for %s." % rpc_request)
return httplib.NOT_FOUND
elif rpc.RPC_MSG_RESULT.SUCCESS == response.result:
return httplib.ACCEPTED
DLOG.error("Unexpected result received for %s, result=%s."
% (rpc_request, response.result))
return httplib.INTERNAL_SERVER_ERROR
@wsme_pecan.wsexpose(None, six.text_type, body=ComputeOperateRequestData,
status_code=httplib.ACCEPTED)
def post(self, compute_id, request_data):
"""
Perform an operation against a virtual compute resource
"""
DLOG.verbose("Compute-API operate called for compute %s, "
"operation=%s." % (compute_id,
request_data.compute_operation))
if not validate.valid_uuid_str(compute_id):
DLOG.error("Invalid uuid received, uuid=%s." % compute_id)
return pecan.abort(httplib.BAD_REQUEST)
http_response = httplib.BAD_REQUEST
if 'start' == request_data.compute_operation:
rpc_request = rpc.APIRequestStartInstance()
rpc_request.uuid = compute_id
http_response = self._do_operation(rpc_request)
elif 'stop' == request_data.compute_operation:
rpc_request = rpc.APIRequestStopInstance()
rpc_request.uuid = compute_id
http_response = self._do_operation(rpc_request)
elif 'pause' == request_data.compute_operation:
rpc_request = rpc.APIRequestPauseInstance()
rpc_request.uuid = compute_id
http_response = self._do_operation(rpc_request)
elif 'unpause' == request_data.compute_operation:
rpc_request = rpc.APIRequestUnpauseInstance()
rpc_request.uuid = compute_id
http_response = self._do_operation(rpc_request)
elif 'suspend' == request_data.compute_operation:
rpc_request = rpc.APIRequestSuspendInstance()
rpc_request.uuid = compute_id
http_response = self._do_operation(rpc_request)
elif 'resume' == request_data.compute_operation:
rpc_request = rpc.APIRequestResumeInstance()
rpc_request.uuid = compute_id
http_response = self._do_operation(rpc_request)
elif 'reboot' == request_data.compute_operation:
rpc_request = rpc.APIRequestRebootInstance()
rpc_request.uuid = compute_id
http_response = self._do_operation(rpc_request)
if httplib.ACCEPTED != http_response:
DLOG.error("Compute operation %s failed for %s, http_response=%s."
% (request_data.compute_operation, compute_id,
http_response))
return pecan.abort(http_response)
ComputeMigrateType = wsme_types.Enum(str, 'live', 'cold', 'evacuate')
class ComputeMigrateRequestData(wsme_types.Base):
"""
Virtualised Resources - Compute Migrate Request Data
"""
migrate_type = wsme_types.wsattr(ComputeMigrateType, mandatory=True)
class ComputeMigrateAPI(pecan.rest.RestController):
"""
Virtualised Resources - Computes Migrate API
"""
@staticmethod
def _do_migrate(rpc_request):
"""
Return an image details
"""
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 %s." % rpc_request)
return httplib.INTERNAL_SERVER_ERROR
response = rpc.RPCMessage.deserialize(msg)
if rpc.RPC_MSG_RESULT.NOT_FOUND == response.result:
DLOG.debug("Resource was not found for %s." % rpc_request)
return httplib.NOT_FOUND
elif rpc.RPC_MSG_RESULT.SUCCESS == response.result:
return httplib.ACCEPTED
DLOG.error("Unexpected result received for %s, result=%s."
% (rpc_request, response.result))
return httplib.INTERNAL_SERVER_ERROR
@wsme_pecan.wsexpose(None, six.text_type, body=ComputeMigrateRequestData,
status_code=httplib.ACCEPTED)
def post(self, compute_id, request_data):
"""
Perform a migrate against a virtual compute resource
"""
DLOG.verbose("Compute-API migrate called for compute %s, "
"migrate_type=%s." % (compute_id,
request_data.migrate_type))
if not validate.valid_uuid_str(compute_id):
DLOG.error("Invalid uuid received, uuid=%s." % compute_id)
return pecan.abort(httplib.BAD_REQUEST)
http_response = httplib.BAD_REQUEST
if 'live' == request_data.migrate_type:
rpc_request = rpc.APIRequestLiveMigrateInstance()
rpc_request.uuid = compute_id
http_response = self._do_migrate(rpc_request)
elif 'cold' == request_data.migrate_type:
rpc_request = rpc.APIRequestColdMigrateInstance()
rpc_request.uuid = compute_id
http_response = self._do_migrate(rpc_request)
elif 'evacuate' == request_data.migrate_type:
rpc_request = rpc.APIRequestEvacuateInstance()
rpc_request.uuid = compute_id
http_response = self._do_migrate(rpc_request)
if httplib.ACCEPTED != http_response:
DLOG.error("Compute migrate %s failed for %s, http_response=%s."
% (request_data.migrate_type, compute_id,
http_response))
return pecan.abort(http_response)
CpuPinningPolicy = wsme_types.Enum(str, 'any', 'static', 'dynamic')
StorageType = wsme_types.Enum(str, 'volume')
class ComputeCreateVirtualCpuPinningType(wsme_types.Base):
"""
Virtualised Resources - Compute Create Virtual CPU Pinning Type
"""
cpu_pinning_policy = wsme_types.wsattr(CpuPinningPolicy, mandatory=False)
cpu_pinning_map = wsme_types.wsattr(six.text_type, mandatory=False)
class ComputeCreateVirtualCpuType(wsme_types.Base):
"""
Virtualised Resources - Compute Create Virtual CPU Type
"""
cpu_architecture = wsme_types.wsattr(six.text_type, mandatory=False)
num_virtual_cpu = wsme_types.wsattr(int, mandatory=True)
virtual_cpu_clock = wsme_types.wsattr(int, mandatory=False)
virtual_cpu_oversubscription_policy = wsme_types.wsattr(six.text_type,
mandatory=False)
virtual_cpu_pinning = wsme_types.wsattr(ComputeCreateVirtualCpuPinningType,
mandatory=False)
class ComputeCreateVirtualMemoryType(wsme_types.Base):
"""
Virtualised Resources - Compute Create Virtual Memory Type
"""
virtual_mem_size = wsme_types.wsattr(int, mandatory=True)
virtual_mem_oversubscription_policy = wsme_types.wsattr(six.text_type,
mandatory=False)
numa_enabled = wsme_types.wsattr(bool, mandatory=False)
class ComputeCreateVirtualStorageType(wsme_types.Base):
"""
Virtualised Resources - Compute Create Virtual Storage Type
"""
type_of_storage = wsme_types.wsattr(StorageType, mandatory=True)
size_of_storage = wsme_types.wsattr(int, mandatory=True)
class ComputeCreateFlavourType(wsme_types.Base):
"""
Virtualised Resources - Compute Create Flavour Type
"""
flavour_id = wsme_types.wsattr(six.text_type, mandatory=True)
virtual_cpu = wsme_types.wsattr(ComputeCreateVirtualCpuType,
mandatory=True)
virtual_memory = wsme_types.wsattr(ComputeCreateVirtualMemoryType,
mandatory=True)
virtual_storage = wsme_types.wsattr(ComputeCreateVirtualStorageType,
mandatory=True)
class ComputeCreateData(wsme_types.Base):
"""
Virtualised Resources - Compute Create Data
"""
compute_id = wsme_types.wsattr(six.text_type, mandatory=True)
reservation_id = wsme_types.wsattr(six.text_type, mandatory=False)
compute_data = wsme_types.wsattr(ComputeCreateFlavourType, mandatory=True)
image_id = wsme_types.wsattr(six.text_type, mandatory=True)
meta_data = wsme_types.wsattr(six.text_type, mandatory=False, default=None)
class ComputeQueryVirtualCpuPinningType(wsme_types.Base):
"""
Virtualised Resources - Compute Query Virtual CPU Pinning Type
"""
cpu_pinning_policy = CpuPinningPolicy
cpu_pinning_map = [six.text_type]
class ComputeQueryVirtualCpuType(wsme_types.Base):
"""
Virtualised Resources - Compute Query Virtual CPU Type
"""
cpu_architecture = six.text_type
num_virtual_cpu = int
virtual_cpu_clock = int
virtual_cpu_oversubscription_policy = six.text_type
virtual_cpu_pinning = ComputeQueryVirtualCpuPinningType
class ComputeQueryVirtualMemoryType(wsme_types.Base):
"""
Virtualised Resources - Compute Query Virtual Memory Type
"""
virtual_mem_size = int
virtual_mem_oversubscription_policy = six.text_type
numa_enabled = bool
class ComputeQueryVirtualStorageType(wsme_types.Base):
"""
Virtualised Resources - Compute Query Virtual Storage Type
"""
type_of_storage = StorageType
size_of_storage = int
class ComputeQueryStorageResourceType(wsme_types.Base):
"""
Virtualised Resources - Compute Query Storage Resource Type
"""
resource_id = six.text_type
storage_attributes = ComputeQueryVirtualStorageType
owner_id = six.text_type
host_id = six.text_type
status = six.text_type
meta_data = six.text_type
class ComputeQueryAttributesResourceType(wsme_types.Base):
"""
Virtualised Resources - Compute Query Attributes Resource Type
"""
flavour_id = six.text_type
acceleration_capabilities = six.text_type
virtual_memory = ComputeQueryVirtualMemoryType
virtual_cpu = ComputeQueryVirtualCpuType
flavour_original_name = six.text_type
class ComputeQueryResourceType(wsme_types.Base):
"""
Virtualised Resources - Compute Query Resource Type
"""
compute_id = six.text_type
compute_attributes = ComputeQueryAttributesResourceType
vc_image_id = six.text_type
virtual_disks = [ComputeQueryStorageResourceType]
host_id = six.text_type
status = six.text_type
meta_data = six.text_type
class ComputeQueryData(wsme_types.Base):
"""
Virtualised Resources - Compute Query Data
"""
query_result = ComputeQueryResourceType
class ComputesAPI(pecan.rest.RestController):
"""
Virtualised Resources - Computes API
"""
operate = ComputeOperateAPI()
migrate = ComputeMigrateAPI()
@staticmethod
def _get_compute_details(compute_id, compute):
"""
Return compute details
"""
vim_connection = pecan.request.vim.open_connection()
rpc_request = rpc.APIRequestGetInstance()
rpc_request.filter_by_uuid = compute_id
vim_connection.send(rpc_request.serialize())
msg = vim_connection.receive()
if msg is None:
DLOG.error("No response received for compute %s." % compute_id)
return httplib.INTERNAL_SERVER_ERROR
response = rpc.RPCMessage.deserialize(msg)
if rpc.RPC_MSG_TYPE.GET_INSTANCE_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("Compute %s was not found." % compute_id)
return httplib.NOT_FOUND
elif rpc.RPC_MSG_RESULT.SUCCESS == response.result:
virtual_memory = ComputeQueryVirtualMemoryType()
virtual_memory.virtual_mem_size = response.memory_mb
virtual_cpu = ComputeQueryVirtualCpuType()
virtual_cpu.num_virtual_cpu = response.vcpus
compute_attributes = ComputeQueryAttributesResourceType()
compute_attributes.flavour_id = ''
compute_attributes.virtual_memory = virtual_memory
compute_attributes.virtual_cpu = virtual_cpu
compute_attributes.flavour_original_name = \
response.instance_type_original_name
query_result = ComputeQueryResourceType()
query_result.compute_id = response.uuid
query_result.compute_attributes = compute_attributes
query_result.host_id = response.host_uuid
query_result.vc_image_id = response.image_uuid
meta_data = dict()
meta_data['sw:wrs:auto_recovery'] = response.auto_recovery
meta_data['hw:wrs:live_migration_timeout'] \
= response.live_migration_timeout
meta_data['hw:wrs:live_migration_max_downtime'] \
= response.live_migration_max_downtime
query_result.meta_data = json.dumps(meta_data)
compute.query_result = query_result
return httplib.OK
DLOG.error("Unexpected result received for compute %s, result=%s."
% (compute_id, response.result))
return httplib.INTERNAL_SERVER_ERROR
@wsme_pecan.wsexpose(ComputeQueryData, six.text_type, status_code=httplib.OK)
def get_one(self, compute_id):
if not validate.valid_uuid_str(compute_id):
DLOG.error("Invalid uuid received, uuid=%s." % compute_id)
return pecan.abort(httplib.BAD_REQUEST)
compute = ComputeQueryData()
http_response = self._get_compute_details(compute_id, compute)
if httplib.OK == http_response:
return compute
else:
return pecan.abort(http_response)
@wsme_pecan.wsexpose([ComputeQueryData], status_code=httplib.OK)
def get_all(self):
DLOG.verbose("Compute-API get-all called.")
vim_connection = pecan.request.vim.open_connection()
rpc_request = rpc.APIRequestGetInstance()
rpc_request.get_all = True
vim_connection.send(rpc_request.serialize())
computes = 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_INSTANCE_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)
virtual_memory = ComputeQueryVirtualMemoryType()
virtual_memory.virtual_mem_size = response.memory_mb
virtual_cpu = ComputeQueryVirtualCpuType()
virtual_cpu.num_virtual_cpu = response.vcpus
compute_attributes = ComputeQueryAttributesResourceType()
compute_attributes.flavour_id = ''
compute_attributes.virtual_memory = virtual_memory
compute_attributes.virtual_cpu = virtual_cpu
compute_attributes.flavour_original_name = \
response.instance_type_original_name
query_result = ComputeQueryResourceType()
query_result.compute_id = response.uuid
query_result.compute_attributes = compute_attributes
query_result.host_id = response.host_uuid
query_result.vc_image_id = response.image_uuid
meta_data = dict()
meta_data['sw:wrs:auto_recovery'] = response.auto_recovery
meta_data['hw:wrs:live_migration_timeout'] \
= response.live_migration_timeout
meta_data['hw:wrs:live_migration_max_downtime'] \
= response.live_migration_max_downtime
query_result.meta_data = json.dumps(meta_data)
compute = ComputeQueryData()
compute.query_result = query_result
computes.append(compute)
return computes
@wsme_pecan.wsexpose(ComputeQueryData, body=ComputeCreateData,
status_code=httplib.CREATED)
def post(self, compute_create_data):
DLOG.verbose("Compute-API create called for compute %s."
% compute_create_data.compute_id)
compute_data = compute_create_data.compute_data
cpu_info = compute_data.virtual_cpu
memory_info = compute_data.virtual_memory
storage_info = compute_data.virtual_storage
if compute_create_data.meta_data is None:
meta_data = dict()
else:
meta_data = json.loads(compute_create_data.meta_data)
vim_connection = pecan.request.vim.open_connection()
rpc_request = rpc.APIRequestCreateInstance()
rpc_request.name = compute_create_data.compute_id
rpc_request.instance_type_uuid = compute_data.flavour_id
rpc_request.image_uuid = compute_create_data.image_id
rpc_request.vcpus = cpu_info.num_virtual_cpu
rpc_request.memory_mb = memory_info.virtual_mem_size
rpc_request.disk_gb = storage_info.size_of_storage
rpc_request.ephemeral_gb = 0
rpc_request.swap_gb = 0
rpc_request.network_uuid = meta_data.get("network_uuid", None)
rpc_request.auto_recovery = meta_data.get("sw:wrs:auto_recovery", None)
rpc_request.live_migration_timeout \
= meta_data.get("hw:wrs:live_migration_timeout", None)
rpc_request.live_migration_max_downtime \
= meta_data.get("hw:wrs:live_migration_max_downtime", None)
vim_connection.send(rpc_request.serialize())
msg = vim_connection.receive()
if msg is None:
DLOG.error("No response received for compute %s."
% compute_create_data.compute_id)
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
response = rpc.RPCMessage.deserialize(msg)
if rpc.RPC_MSG_TYPE.CREATE_INSTANCE_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:
virtual_memory = ComputeQueryVirtualMemoryType()
virtual_memory.virtual_mem_size = response.memory_mb
virtual_cpu = ComputeQueryVirtualCpuType()
virtual_cpu.num_virtual_cpu = response.vcpus
compute_attributes = ComputeQueryAttributesResourceType()
compute_attributes.flavour_id = ''
compute_attributes.virtual_memory = virtual_memory
compute_attributes.virtual_cpu = virtual_cpu
compute_attributes.flavour_original_name = \
response.instance_type_original_name
query_result = ComputeQueryResourceType()
query_result.compute_id = response.uuid
query_result.compute_attributes = compute_attributes
query_result.host_id = response.host_uuid
query_result.vc_image_id = response.image_uuid
meta_data = dict()
meta_data['sw:wrs:auto_recovery'] = response.auto_recovery
meta_data['hw:wrs:live_migration_timeout'] \
= response.live_migration_timeout
meta_data['hw:wrs:live_migration_max_downtime'] \
= response.live_migration_max_downtime
query_result.meta_data = json.dumps(meta_data)
compute = ComputeQueryData()
compute.query_result = query_result
return compute
DLOG.error("Unexpected result received for compute %s, result=%s."
% (compute_create_data.compute_id, response.result))
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
@wsme_pecan.wsexpose(None, six.text_type, status_code=httplib.NO_CONTENT)
def delete(self, compute_id):
DLOG.verbose("Compute-API delete called for compute %s." % compute_id)
vim_connection = pecan.request.vim.open_connection()
rpc_request = rpc.APIRequestDeleteInstance()
rpc_request.uuid = compute_id
vim_connection.send(rpc_request.serialize())
msg = vim_connection.receive()
if msg is None:
DLOG.error("No response received for instance %s." % compute_id)
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
response = rpc.RPCMessage.deserialize(msg)
if rpc.RPC_MSG_TYPE.DELETE_INSTANCE_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("Instance %s was not found." % compute_id)
return pecan.abort(httplib.NOT_FOUND)
elif rpc.RPC_MSG_RESULT.SUCCESS == response.result:
return None
DLOG.error("Unexpected result received for instance %s, result=%s."
% (compute_id, response.result))
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)