summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--pom.xml2
-rw-r--r--vio/images/empty.txt0
-rw-r--r--vio/requirements.txt3
-rw-r--r--vio/vio/middleware.py59
-rw-r--r--vio/vio/pub/config/config.py33
-rw-r--r--vio/vio/pub/config/log.yml8
-rwxr-xr-xvio/vio/pub/utils/share_lock.py82
-rw-r--r--vio/vio/pub/vim/drivers/vimsdk/image_v2.py12
-rw-r--r--vio/vio/pub/vim/vimapi/glance/OperateImage.py52
-rw-r--r--vio/vio/pub/vim/vimapi/nova/OperateHypervisor.py4
-rw-r--r--vio/vio/settings.py2
-rw-r--r--vio/vio/swagger/urls.py16
-rw-r--r--vio/vio/swagger/views/capacity/__init__.py0
-rw-r--r--vio/vio/swagger/views/capacity/views.py123
-rw-r--r--vio/vio/swagger/views/image/views.py108
-rw-r--r--vio/vio/tests/test_capacity_view.py111
-rw-r--r--vio/vio/urls.py10
18 files changed, 496 insertions, 131 deletions
diff --git a/.gitignore b/.gitignore
index bd4f0b0..44b3469 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,12 @@
.project
.classpath
+.vscode
.settings/
.checkstyle
target/
logs/*.log
*.pyc
+*.swp
# Test related files
vio/.coverage
diff --git a/pom.xml b/pom.xml
index a52ab10..a8c052c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,7 +18,7 @@
<parent>
<groupId>org.onap.oparent</groupId>
<artifactId>oparent</artifactId>
- <version>0.1.1</version>
+ <version>1.1.0</version>
<relativePath>../oparent</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
diff --git a/vio/images/empty.txt b/vio/images/empty.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/vio/images/empty.txt
diff --git a/vio/requirements.txt b/vio/requirements.txt
index 8d5a51c..32384a9 100644
--- a/vio/requirements.txt
+++ b/vio/requirements.txt
@@ -14,6 +14,7 @@ httplib2==0.9.2
# for call openstack api
openstacksdk==0.9.14
+python-cinderclient==3.5.0
# for unit test
django-nose>=1.4.0
@@ -22,4 +23,4 @@ mock==2.0.0
unittest_xml_reporting==1.12.0
# for onap logging
-onappylog>=1.0.5
+onappylog>=1.0.6
diff --git a/vio/vio/middleware.py b/vio/vio/middleware.py
new file mode 100644
index 0000000..161562e
--- /dev/null
+++ b/vio/vio/middleware.py
@@ -0,0 +1,59 @@
+# Copyright (c) 2017-2018 VMware, Inc.
+#
+# 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.
+
+
+import uuid
+from onaplogging.mdcContext import MDC
+from vio.pub.config.config import SERVICE_NAME
+from vio.pub.config.config import FORWARDED_FOR_FIELDS
+
+
+class LogContextMiddleware(object):
+
+ # the last IP behind multiple proxies, if no exist proxies
+ # get local host ip.
+ def _getLastIp(self, request):
+
+ ip = ""
+ try:
+ for field in FORWARDED_FOR_FIELDS:
+ if field in request.META:
+ if ',' in request.META[field]:
+ parts = request.META[field].split(',')
+ ip = parts[-1].strip().split(":")[0]
+ else:
+ ip = request.META[field].split(":")[0]
+
+ if ip == "":
+ ip = request.META.get("HTTP_HOST").split(":")[0]
+
+ except Exception:
+ pass
+
+ return ip
+
+ def process_request(self, request):
+
+ ReqeustID = request.META.get("HTTP_X_TRANSACTIONID", None)
+ if ReqeustID is None:
+ ReqeustID = uuid.uuid3(uuid.NAMESPACE_URL, SERVICE_NAME)
+ MDC.put("requestID", ReqeustID)
+ InovocationID = uuid.uuid3(uuid.NAMESPACE_DNS, SERVICE_NAME)
+ MDC.put("invocationID", InovocationID)
+ MDC.put("serviceName", SERVICE_NAME)
+ MDC.put("serviceIP", self._getLastIp(request))
+ return None
+
+ def process_response(self, request, response):
+
+ MDC.clear()
+ return response
diff --git a/vio/vio/pub/config/config.py b/vio/vio/pub/config/config.py
index 2b35e54..9b4d6c8 100644
--- a/vio/vio/pub/config/config.py
+++ b/vio/vio/pub/config/config.py
@@ -24,34 +24,11 @@ ROOT_PATH = os.path.dirname(os.path.dirname(
AAI_ADDR = "aai.api.simpledemo.openecomp.org"
AAI_PORT = "8443"
AAI_SERVICE_URL = 'https://%s:%s/aai' % (AAI_ADDR, AAI_PORT)
-AAI_SCHEMA_VERSION = "v11"
+AAI_SCHEMA_VERSION = "v13"
AAI_USERNAME = 'AAI'
AAI_PASSWORD = 'AAI'
-# [REDIS]
-REDIS_HOST = '127.0.0.1'
-REDIS_PORT = '6379'
-REDIS_PASSWD = ''
-
-# [mysql]
-# DB_IP = '127.0.0.1'
-# DB_PORT = 3306
-# DB_NAME = 'multivimvio'
-# DB_USER = 'root'
-# DB_PASSWD = 'password'
-
-# [register]
-REG_TO_MSB_WHEN_START = False
-REG_TO_MSB_REG_URL = "/api/microservices/v1/services"
-REG_TO_MSB_REG_PARAM = {
- "serviceName": "multicloud-vio",
- "version": "v0",
- "url": "/api/multicloud-vio/v0",
- "protocol": "REST",
- "visualRange": "1",
- "nodes": [{
- "ip": "127.0.0.1",
- "port": "9004",
- "ttl": 0
- }]
-}
+# [MDC]
+SERVICE_NAME = "multicloud-vio"
+FORWARDED_FOR_FIELDS = ["HTTP_X_FORWARDED_FOR", "HTTP_X_FORWARDED_HOST",
+ "HTTP_X_FORWARDED_SERVER"]
diff --git a/vio/vio/pub/config/log.yml b/vio/vio/pub/config/log.yml
index 82eb814..5cced4f 100644
--- a/vio/vio/pub/config/log.yml
+++ b/vio/vio/pub/config/log.yml
@@ -12,14 +12,14 @@ handlers:
class: "logging.handlers.RotatingFileHandler"
filename: "/var/log/onap/multicloud/vio/vio.log"
formatter: "mdcFormat"
- maxBytes: 1024*1024*50
+ maxBytes: 52428800
backupCount: 10
formatters:
standard:
- format: "%(asctime)s:[%(name)s]:[%(filename)s]-[%(lineno)d] [%(levelname)s]:%(message)s"
+ format: "%(asctime)s|||||%(name)s||%(thread)||%(funcName)s||%(levelname)s||%(message)s"
mdcFormat:
- format: "%(asctime)s:[%(name)s]:[%(filename)s]-[%(lineno)d] [%(levelname)s]:[%(mdc)s]: %(message)s"
- mdcfmt: "{requestID}"
+ format: "%(asctime)s|||||%(name)s||%(thread)s||%(funcName)s||%(levelname)s||%(message)s||||%(mdc)s \t"
+ mdcfmt: "{requestID} {invocationID} {serviceName} {serviceIP}"
datefmt: "%Y-%m-%d %H:%M:%S"
(): onaplogging.mdcformatter.MDCFormatter
diff --git a/vio/vio/pub/utils/share_lock.py b/vio/vio/pub/utils/share_lock.py
deleted file mode 100755
index 0e015c5..0000000
--- a/vio/vio/pub/utils/share_lock.py
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017-2018 VMware, Inc.
-#
-# 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.
-
-import time
-
-import redis
-
-from vio.pub.config.config import REDIS_HOST, REDIS_PORT, REDIS_PASSWD
-
-
-class SharedLock:
- def __init__(self, lock_key, host=REDIS_HOST, port=REDIS_PORT,
- password=REDIS_PASSWD, db=9, lock_timeout=5 * 60):
- self.lock_key = lock_key
- self.lock_timeout = lock_timeout
- self.redis = redis.Redis(host=host, port=port,
- db=db, password=password)
- self.acquire_time = -1
-
- def acquire(self):
- begin = now = int(time.time())
- while (now - begin) < self.lock_timeout:
-
- result = self.redis.setnx(
- self.lock_key, now + self.lock_timeout + 1)
- if result == 1 or result is True:
- self.acquire_time = now
- return True
-
- current_lock_timestamp = self.redis.get(self.lock_key)
- if not current_lock_timestamp:
- time.sleep(1)
- continue
-
- current_lock_timestamp = int(current_lock_timestamp)
-
- if now > current_lock_timestamp:
- next_lock_timestamp = self.redis.getset(
- self.lock_key, now + self.lock_timeout + 1)
- if not next_lock_timestamp:
- time.sleep(1)
- continue
- next_lock_timestamp = int(next_lock_timestamp)
-
- if next_lock_timestamp == current_lock_timestamp:
- self.acquire_time = now
- return True
- else:
- time.sleep(1)
- continue
- return False
-
- def release(self):
- now = int(time.time())
- if now > self.acquire_time + self.lock_timeout:
- # key expired, do nothing and let other clients handle it
- return
- self.acquire_time = None
- self.redis.delete(self.lock_key)
-
-
-def do_biz_with_share_lock(lock_name, callback):
- lock = SharedLock(lock_name)
- try:
- if not lock.acquire():
- raise Exception(lock_name + " timeout")
- callback()
- except Exception as e:
- raise e
- finally:
- lock.release()
diff --git a/vio/vio/pub/vim/drivers/vimsdk/image_v2.py b/vio/vio/pub/vim/drivers/vimsdk/image_v2.py
index f185e35..a7034cf 100644
--- a/vio/vio/pub/vim/drivers/vimsdk/image_v2.py
+++ b/vio/vio/pub/vim/drivers/vimsdk/image_v2.py
@@ -65,3 +65,15 @@ class GlanceClient(base.DriverBase):
def upload_image(self, data, image):
image.data = data
image.upload(self.session)
+
+ @sdk.translate_exception
+ def create_image_file(self, file_name, image_type):
+
+ img = self._proxy._create(_image.Image, disk_format=image_type,
+ container_format='bare', name=file_name)
+ return img
+
+ @sdk.translate_exception
+ def download_image(self, image):
+ img = image.download(self.session, stream=True)
+ return img
diff --git a/vio/vio/pub/vim/vimapi/glance/OperateImage.py b/vio/vio/pub/vim/vimapi/glance/OperateImage.py
index 35deb4c..ddb7ba2 100644
--- a/vio/vio/pub/vim/vimapi/glance/OperateImage.py
+++ b/vio/vio/pub/vim/vimapi/glance/OperateImage.py
@@ -15,14 +15,12 @@ import logging
import threading
import urllib2
-
from vio.pub.msapi import extsys
from vio.pub.vim.vimapi.baseclient import baseclient
from vio.swagger import image_utils
logger = logging.getLogger(__name__)
-
running_threads = {}
running_thread_lock = threading.Lock()
@@ -102,3 +100,53 @@ class OperateImage(baseclient):
except Exception:
pass
return image
+
+ def create_vim_image_file(self, vimid, tenantid, file_name,
+ file_dest, image_type):
+
+ image = self.glance(self.param).create_image_file(file_name,
+ image_type)
+ upload_image_file_thread = imagefileThread(vimid, tenantid,
+ image, file_dest)
+ logger.debug("launch thread to upload image: %s" % image.id)
+ running_thread_lock.acquire()
+ running_threads[image.id] = image.id
+ running_thread_lock.release()
+ try:
+ upload_image_file_thread.start()
+ except Exception:
+ pass
+ return image
+
+ def download_vim_image(self, image):
+
+ image_data = self.glance(self.param).download_image(image)
+ return image_data
+
+
+class imagefileThread(threading.Thread):
+ def __init__(self, vimid, tenantid, image, file_dest):
+
+ threading.Thread.__init__(self)
+ self.imageid = image.id
+ self.vimid = vimid
+ self.tenantid = tenantid
+ self.image = image
+ self.file_dest = file_dest
+
+ def run(self):
+
+ logger.debug("start imagethread")
+ self.transfer_image_file(self.vimid, self.tenantid,
+ self.image, self.file_dest)
+ running_thread_lock.acquire()
+ running_threads.pop(self.imageid)
+ running_thread_lock.release()
+
+ def transfer_image_file(self, vimid, tenantid, image, file_dest):
+ logger.debug("Image----transfer_image")
+ vim_info = extsys.get_vim_by_id(vimid)
+ vim_info['tenant'] = tenantid
+ param = image_utils.sdk_param_formatter(vim_info)
+ client = baseclient()
+ client.glance(param).upload_image(open(file_dest), image)
diff --git a/vio/vio/pub/vim/vimapi/nova/OperateHypervisor.py b/vio/vio/pub/vim/vimapi/nova/OperateHypervisor.py
index a9ad572..1249162 100644
--- a/vio/vio/pub/vim/vimapi/nova/OperateHypervisor.py
+++ b/vio/vio/pub/vim/vimapi/nova/OperateHypervisor.py
@@ -24,7 +24,7 @@ class OperateHypervisor(OperateNova):
def get_hypervisor(self, data, hypervisor, **kwargs):
try:
return self.request('get_hypervisor', data,
- project_id=data['project_id'],
+ project_id=data.get('project_id'),
hypervisor=hypervisor,
**kwargs)
except exceptions.ResourceNotFound:
@@ -33,7 +33,7 @@ class OperateHypervisor(OperateNova):
def list_hypervisors(self, data, **query):
try:
return self.request('list_hypervisors', data,
- project_id=data['project_id'],
+ project_id=data.get('project_id'),
**query)
except exceptions.ResourceNotFound:
return None
diff --git a/vio/vio/settings.py b/vio/vio/settings.py
index e82b523..f1dad0f 100644
--- a/vio/vio/settings.py
+++ b/vio/vio/settings.py
@@ -51,6 +51,7 @@ MIDDLEWARE_CLASSES = [
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
+ 'vio.middleware.LogContextMiddleware',
]
ROOT_URLCONF = 'vio.urls'
@@ -94,7 +95,6 @@ config.yamlConfig(filepath=LOGGING_FILE, watchDog=True)
if 'test' in sys.argv:
from vio.pub.config import config
- config.REG_TO_MSB_WHEN_START = False
DATABASES = {}
DATABASES['default'] = {
'ENGINE': 'django.db.backends.sqlite3',
diff --git a/vio/vio/swagger/urls.py b/vio/vio/swagger/urls.py
index 89a5974..3871599 100644
--- a/vio/vio/swagger/urls.py
+++ b/vio/vio/swagger/urls.py
@@ -20,6 +20,8 @@ from vio.swagger.views.swagger_json import SwaggerJsonView
from vio.swagger.views.tenant.views import ListTenantsView
from vio.swagger.views.image.views import CreateListImagesView
from vio.swagger.views.image.views import GetDeleteImageView
+from vio.swagger.views.image.views import CreateImageFileView
+from vio.swagger.views.image.views import GetImageFileView
from vio.swagger.views.volume.views import CreateListVolumeView
from vio.swagger.views.volume.views import GetDeleteVolumeView
from vio.swagger.views.server.views import ListServersView, GetServerView
@@ -48,6 +50,9 @@ from vio.swagger.views.proxyplugin.dns.views import DesignateVersionLink
from vio.swagger.views.registry.views import Registry
from vio.swagger.views.registry.views import UnRegistry
+# Capacity Check
+from vio.swagger.views.capacity.views import CapacityCheck
+
# Extensions
from vio.swagger.views.extensions.views import Extensions
@@ -96,6 +101,13 @@ urlpatterns = [
r'(?P<tenantid>[0-9a-zA-Z_-]+)/images/(?P<imageid>[0-9a-zA-Z_-]+)$',
GetDeleteImageView.as_view()),
url(r'^api/multicloud-vio/v0/(?P<vimid>[0-9a-zA-Z_-]+)/'
+ r'(?P<tenantid>[0-9a-zA-Z_-]+)/images/file$',
+ CreateImageFileView.as_view()),
+ url(r'^api/multicloud-vio/v0/(?P<vimid>[0-9a-zA-Z_-]+)/'
+ r'(?P<tenantid>[0-9a-zA-Z_-]+)/images/file/'
+ r'(?P<imageid>[0-9a-zA-Z_-]+)$',
+ GetImageFileView.as_view()),
+ url(r'^api/multicloud-vio/v0/(?P<vimid>[0-9a-zA-Z_-]+)/'
r'(?P<tenantid>[0-9a-zA-Z_-]+)/volumes$',
CreateListVolumeView.as_view()),
url(r'^api/multicloud-vio/v0/(?P<vimid>[0-9a-zA-Z_-]+)/'
@@ -229,6 +241,10 @@ urlpatterns = [
url(r'^api/multicloud-vio/v0/(?P<vimid>[0-9a-z-A-Z\-\_]+)$',
UnRegistry.as_view()),
+ # CapacityCheck
+ url(r'^api/multicloud-vio/v0/(?P<vimid>[0-9a-z-A-Z\-\_]+)/capacity_check$',
+ CapacityCheck.as_view()),
+
# proxy
url(r'^api/multicloud-vio/v0/(?P<vimid>[0-9a-z-A-Z\-\_]+)/identity/v3',
TokenView.as_view()),
diff --git a/vio/vio/swagger/views/capacity/__init__.py b/vio/vio/swagger/views/capacity/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/vio/vio/swagger/views/capacity/__init__.py
diff --git a/vio/vio/swagger/views/capacity/views.py b/vio/vio/swagger/views/capacity/views.py
new file mode 100644
index 0000000..1fdc481
--- /dev/null
+++ b/vio/vio/swagger/views/capacity/views.py
@@ -0,0 +1,123 @@
+# Copyright (c) 2017-2018 VMware, Inc.
+#
+# 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.
+
+import json
+import logging
+
+from rest_framework import status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+
+from vio.pub.exceptions import VimDriverVioException
+from vio.pub.msapi import extsys
+from vio.pub.vim.vimapi.nova import OperateHypervisor
+from vio.pub.vim.vimapi.nova import OperateLimits
+
+from cinderclient import client
+
+
+logger = logging.getLogger(__name__)
+
+
+class CapacityCheck(APIView):
+
+ def _check_capacity(self, hypervisor, requirement):
+ avail_vcpu = hypervisor.get("vcpus") - hypervisor.get("vcpus_used")
+ avail_mem = (hypervisor.get("memory_size") - hypervisor.get(
+ "memory_used"))/1024
+ avail_disk = hypervisor.get("local_disk_size") - hypervisor.get(
+ "local_disk_used")
+ req_vcpu = requirement.get("vCPU")
+ req_mem = requirement.get("Memory")
+ req_disk = requirement.get("Storage")
+ if avail_vcpu < req_vcpu:
+ return False
+ if avail_mem < req_mem:
+ return False
+ if avail_disk < req_disk:
+ return False
+ return True
+
+ def _check_nova_limits(self, limits, requirement):
+ avail_vcpu = (
+ limits.absolute.total_cores - limits.absolute.total_cores_used)
+ avail_mem = (
+ limits.absolute.total_ram - limits.absolute.total_ram_used)/1024
+ req_vcpu = requirement.get("vCPU")
+ req_mem = requirement.get("Memory")
+ if avail_vcpu >= 0 and avail_vcpu < req_vcpu:
+ return False
+ if avail_mem >= 0 and avail_mem < req_mem:
+ return False
+ return True
+
+ def _check_cinder_limits(self, limits, requirement):
+ absolute = limits['absolute']
+ avail_disk = (absolute.get(
+ "maxTotalVolumeGigabytes") - absolute.get("totalGigabytesUsed"))
+ req_disk = requirement.get("Storage")
+ if avail_disk < req_disk:
+ return False
+ return True
+
+ def post(self, request, vimid):
+ try:
+ requirement = json.loads(request.body)
+ except ValueError as ex:
+ return Response(data={'error': str(ex)},
+ status=status.HTTP_400_BAD_REQUEST)
+ try:
+ vim_info = extsys.get_vim_by_id(vimid)
+ except VimDriverVioException as e:
+ return Response(data={'error': str(e)}, status=e.status_code)
+ auth_info = {
+ "username": vim_info['userName'],
+ "password": vim_info['password'],
+ "url": vim_info['url'],
+ "project_name": vim_info['tenant']
+ }
+
+ # check nova limits
+ servers_op = OperateLimits.OperateLimits()
+ try:
+ nova_limits = servers_op.get_limits(auth_info, None)
+ except Exception as e:
+ logger.exception("get nova limits error %(e)s", {"e": e})
+ return Response(data={'error': str(e)}, status=e.status_code)
+ if not self._check_nova_limits(nova_limits, requirement):
+ return Response(
+ data={'result': False}, status=status.HTTP_200_OK)
+ # check cinder limits
+ cinder = client.Client(
+ "2", auth_info['username'], auth_info['password'],
+ auth_info['project_name'], auth_info['url'], insecure=True)
+ try:
+ limits = cinder.limits.get().to_dict()
+ except Exception as e:
+ logger.exception("get cinder limits error %(e)s", {"e": e})
+ return Response(data={'error': str(e)}, status=e.status_code)
+ if not self._check_cinder_limits(limits, requirement):
+ return Response(
+ data={'result': False}, status=status.HTTP_200_OK)
+ # check hypervisor resources
+ hypervisor_op = OperateHypervisor.OperateHypervisor()
+ try:
+ hypervisors = hypervisor_op.list_hypervisors(auth_info)
+ except Exception as e:
+ logger.exception("get hypervisors error %(e)s", {"e": e})
+ return Response(data={'error': str(e)}, status=e.status_code)
+ for hypervisor in hypervisors:
+ hyper = hypervisor_op.get_hypervisor(auth_info, hypervisor.id)
+ if self._check_capacity(hyper.to_dict(), requirement):
+ return Response(data={'result': True},
+ status=status.HTTP_200_OK)
+ return Response(data={'result': False}, status=status.HTTP_200_OK)
diff --git a/vio/vio/swagger/views/image/views.py b/vio/vio/swagger/views/image/views.py
index 26914cf..62770c7 100644
--- a/vio/vio/swagger/views/image/views.py
+++ b/vio/vio/swagger/views/image/views.py
@@ -11,6 +11,9 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import json
+import random
+import string
+import sys
from rest_framework import status
from rest_framework.response import Response
@@ -135,3 +138,108 @@ class CreateListImagesView(APIView):
else:
return Response(data={'error': str(e)},
status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+class CreateImageFileView(APIView):
+
+ def post(self, request, vimid, tenantid):
+
+ try:
+ vim_info = extsys.get_vim_by_id(vimid)
+ vim_info['tenant'] = tenantid
+ except VimDriverVioException as e:
+ return Response(data={'error': str(e)}, status=e.status_code)
+
+ vim_rsp = image_utils.vim_formatter(vim_info, tenantid)
+ image_instance = OperateImage.OperateImage(vim_info)
+
+ try:
+ image_file = request.FILES['file']
+
+ random_name = ''.join(random.sample(
+ string.ascii_letters
+ + string.digits, 4))
+ file_name = image_file.name[:image_file.name.rfind('.')]
+ + "_" + random_name
+ + image_file.name[image_file.name.find('.'):]
+
+ file_dest = sys.path[0] + '/images/' + file_name
+ with open(file_dest, 'wb+') as temp_file:
+ for chunk in image_file.chunks():
+ temp_file.write(chunk)
+ temp_file.close()
+
+ image_type = image_file.name[image_file.name.find('.') + 1:]
+
+ except Exception as e:
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ try:
+ image = image_instance.create_vim_image_file(
+ vimid, tenantid,
+ file_name[:file_name.rfind('.')],
+ file_dest,
+ image_type)
+ rsp = image_utils.image_formatter(image)
+ rsp.update(vim_rsp)
+ rsp['returnCode'] = '1'
+
+ return Response(data={'status': rsp},
+ status=status.HTTP_201_CREATED)
+ except Exception as e:
+ if hasattr(e, "http_status"):
+ return Response(data={'error': str(e)}, status=e.http_status)
+ else:
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+class GetImageFileView(APIView):
+
+ def post(self, request, vimid, tenantid, imageid):
+ try:
+ vim_info = extsys.get_vim_by_id(vimid)
+ vim_info['tenant'] = tenantid
+ except VimDriverVioException as e:
+ return Response(data={'error': str(e)}, status=e.status_code)
+
+ try:
+ req_body = json.loads(request.body)
+ except Exception as e:
+ return Response(data={'error': 'Fail to decode request body.'},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ vim_rsp = image_utils.vim_formatter(vim_info, tenantid)
+ image_instance = OperateImage.OperateImage(vim_info)
+ try:
+ image = image_instance.find_vim_image(imageid)
+ except Exception as e:
+ return Response(data={'error': 'the image does not exist'},
+ status=status.HTTP_404_NOT_FOUND)
+
+ try:
+ image_data = image_instance.download_vim_image(image)
+
+ imagePath = req_body.get('imagePath')
+ if imagePath[-1:] is not '/':
+ imagePath += '/'
+ file_name = "%s%s.%s" % (imagePath, image.name, image.disk_format)
+ image_file = open(file_name, 'w+')
+
+ for chunk in image_data:
+ image_file.write(chunk)
+ image_file.close()
+
+ rsp = image_utils.image_formatter(image)
+ rsp.update(vim_rsp)
+ rsp['returnCode'] = '1'
+
+ return Response(data={'status': rsp},
+ status=status.HTTP_200_OK)
+
+ except Exception as e:
+ if hasattr(e, "http_status"):
+ return Response(data={'error': str(e)}, status=e.http_status)
+ else:
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
diff --git a/vio/vio/tests/test_capacity_view.py b/vio/vio/tests/test_capacity_view.py
new file mode 100644
index 0000000..d27efba
--- /dev/null
+++ b/vio/vio/tests/test_capacity_view.py
@@ -0,0 +1,111 @@
+# Copyright (c) 2017-2018 VMware, Inc.
+#
+# 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.
+
+import mock
+import unittest
+
+from rest_framework import status
+
+from vio.pub.msapi import extsys
+from vio.pub.vim.vimapi.nova import OperateHypervisor
+from vio.pub.vim.vimapi.nova import OperateLimits
+from vio.swagger.views.capacity.views import CapacityCheck
+
+from cinderclient import client
+
+
+VIM_INFO = {'vimId': 1, 'name': 'openstack_regionone', 'userName': 'user1',
+ 'password': '1234', 'url': 'abc', 'tenant': 't1'}
+
+
+class CapacityCheckTest(unittest.TestCase):
+
+ def setUp(self):
+ self.view = CapacityCheck()
+
+ @mock.patch.object(OperateHypervisor, "OperateHypervisor")
+ @mock.patch.object(OperateLimits, "OperateLimits")
+ @mock.patch.object(client, "Client")
+ @mock.patch.object(extsys, "get_vim_by_id")
+ def test_check_capacity_success(self, mock_get_vim, mock_cinder,
+ mock_limit, mock_hypervisor):
+ mock_get_vim.return_value = VIM_INFO
+ req = mock.Mock()
+ req.body = """{
+ "vCPU": 1,
+ "Memory": 1,
+ "Storage": 500
+ }"""
+ oplimits = mock.Mock()
+ absolute = mock.Mock(
+ total_cores=20, total_cores_used=1,
+ total_ram=128*1024, total_ram_used=4*1024)
+ oplimits.get_limits.return_value = mock.Mock(absolute=absolute)
+ mock_limit.return_value = oplimits
+
+ climits = mock.Mock()
+ climits.to_dict.return_value = {
+ "absolute": {
+ "maxTotalVolumeGigabytes": 5000,
+ "totalGigabytesUsed": 100
+ }
+ }
+ cclient = mock.Mock()
+ cclient.limits.get.return_value = climits
+ mock_cinder.return_value = cclient
+
+ ophypervisor = mock.Mock()
+ ophypervisor.list_hypervisors.return_value = [
+ mock.Mock(id="compute01")]
+ hyper = mock.Mock()
+ hyper.to_dict.return_value = {
+ "vcpus": 20,
+ "vcpus_used": 1,
+ "memory_size": 128*1024,
+ "memory_used": 4*1024,
+ "local_disk_size": 5000,
+ "local_disk_used": 100
+ }
+ ophypervisor.get_hypervisor.return_value = hyper
+ mock_hypervisor.return_value = ophypervisor
+ resp = self.view.post(req, "openstack_regionone")
+ self.assertEqual(status.HTTP_200_OK, resp.status_code)
+ self.assertEqual({"result": True}, resp.data)
+
+ @mock.patch.object(OperateLimits, "OperateLimits")
+ @mock.patch.object(extsys, "get_vim_by_id")
+ def test_check_capacity_nova_limits_failed(
+ self, mock_get_vim, mock_limit):
+ mock_get_vim.return_value = VIM_INFO
+ req = mock.Mock()
+ req.body = """{
+ "vCPU": 1,
+ "Memory": 1,
+ "Storage": 500
+ }"""
+ oplimits = mock.Mock()
+ absolute = mock.Mock(
+ total_cores=1, total_cores_used=1,
+ total_ram=128*1024, total_ram_used=4*1024)
+ oplimits.get_limits.return_value = mock.Mock(absolute=absolute)
+ mock_limit.return_value = oplimits
+
+ resp = self.view.post(req, "openstack_regionone")
+ self.assertEqual(status.HTTP_200_OK, resp.status_code)
+ self.assertEqual({"result": False}, resp.data)
+
+ def test_check_capacity_invalid_input(self):
+ req = mock.Mock()
+ req.body = "hello world"
+
+ resp = self.view.post(req, "openstack_regionone")
+ self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code)
diff --git a/vio/vio/urls.py b/vio/vio/urls.py
index 9166774..85b3d9c 100644
--- a/vio/vio/urls.py
+++ b/vio/vio/urls.py
@@ -11,18 +11,8 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
from django.conf.urls import include, url
-from vio.pub.config.config import REG_TO_MSB_WHEN_START
-from vio.pub.config.config import REG_TO_MSB_REG_URL
-from vio.pub.config.config import REG_TO_MSB_REG_PARAM
urlpatterns = [
url(r'^', include('vio.swagger.urls')),
url(r'^', include('vio.samples.urls')),
]
-
-# regist to MSB when startup
-if REG_TO_MSB_WHEN_START:
- import json
- from vio.pub.utils.restcall import req_by_msb
- req_by_msb(REG_TO_MSB_REG_URL, "POST",
- json.JSONEncoder().encode(REG_TO_MSB_REG_PARAM))