From 0fc4bfecefc6fed785147174253ee47dd540f5d4 Mon Sep 17 00:00:00 2001 From: Bin Yang Date: Mon, 6 Mar 2017 20:14:31 +0800 Subject: Implement servers API for newton Change-Id: Iad72f45cf0d7696e277c03347e2bf0bf7de50e6c Issue-Id: MULTIVIM-22 Signed-off-by: Bin Yang --- newton/newton/requests/urls.py | 3 + newton/newton/requests/views/server.py | 260 +++++++++++++++++++++++++++++++++ 2 files changed, 263 insertions(+) create mode 100644 newton/newton/requests/views/server.py (limited to 'newton/newton/requests') diff --git a/newton/newton/requests/urls.py b/newton/newton/requests/urls.py index 510e3810..77045340 100644 --- a/newton/newton/requests/urls.py +++ b/newton/newton/requests/urls.py @@ -19,6 +19,7 @@ from views import network from views import subnet from views import image from views import volume +from views import server from views import vport from views import limits from views import hosts @@ -33,6 +34,8 @@ urlpatterns = [ image.Images.as_view()), url(r'^volumes(/(?P[0-9a-zA-Z_-]+))?', volume.Volumes.as_view()), + url(r'^servers(/(?P[0-9a-zA-Z_-]+))?', + server.Servers.as_view()), url(r'^ports(/(?P[0-9a-zA-Z_-]+))?', vport.Vports.as_view()), url(r'^flavors(/(?P[0-9a-zA-Z_-]+))?', diff --git a/newton/newton/requests/views/server.py b/newton/newton/requests/views/server.py new file mode 100644 index 00000000..26f30de1 --- /dev/null +++ b/newton/newton/requests/views/server.py @@ -0,0 +1,260 @@ +# Copyright (c) 2017 Wind River Systems, 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. +# See the License for the specific language governing permissions and +# limitations under the License. +import logging +import json + +from rest_framework import status +from rest_framework.response import Response +from rest_framework.views import APIView + +from newton.pub.exceptions import VimDriverNewtonException + +from util import VimDriverUtils + +logger = logging.getLogger(__name__) + + +class Servers(APIView): + service = {'service_type': 'compute', + 'interface': 'public', + 'region_name': 'RegionOne'} + keys_mapping = [ + ("tenant_id", "tenantId"), + ("flavorRef", "flavorId"), + ("user_data", "userdata"), + ("security_groups", "securityGroups"), + ("availability_zone ", "availabilityZone"), + ] + + service_volume = {'service_type': 'volumev2', + 'interface': 'public', + 'region_name': 'RegionOne'} + + def attachVolume(self, sess, serverId, volumeId): + req_resouce = "volumes" + if volumeId: + req_resouce += "/%s/action" % volumeId + + req_data = {"os-attach": { + "instance_uuid": serverId + }} + req_body = json.JSONEncoder().encode(req_data) + resp = sess.post(req_resouce, data=req_body, + endpoint_filter=self.service, headers={"Content-Type": "application/json", + "Accept": "application/json"}) + pass + + def convertMetadata(self, metadata, mata_data, reverse=False): + if reverse == False: + # from extraSpecs to extra_specs + for spec in metadata: + mata_data[spec['keyName']] = spec['value'] + else: + for k, v in mata_data.items(): + spec = {} + spec['keyName'] = k + spec['value'] = v + metadata.append(spec) + + pass + + def get(self, request, vimid="", tenantid="", serverid=""): + logger.debug("Servers--get::> %s" % request.data) + try: + # prepare request resource to vim instance + query = VimDriverUtils.get_query_part(request) + content, status_code = self.get_servers(query, vimid, tenantid, serverid) + return Response(data=content, status=status_code) + except VimDriverNewtonException as e: + return Response(data={'error': e.content}, status=e.status_code) + except Exception as e: + return Response(data={'error': str(e)}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + def get_servers(self, query="", vimid="", tenantid="", serverid=None): + logger.debug("Servers--get_servers::> %s,%s" % (tenantid, serverid)) + + # prepare request resource to vim instance + req_resouce = "servers" + if serverid: + req_resouce += "/%s" % serverid + else: + req_resouce += "/detail" + if query: + req_resouce += "?%s" % query + + vim = VimDriverUtils.get_vim_info(vimid) + sess = VimDriverUtils.get_session(vim, tenantid) + resp = sess.get(req_resouce, endpoint_filter=self.service) + content = resp.json() + vim_dict = { + "vimName": vim["name"], + "vimId": vim["vimId"], + "tenantId": tenantid, + } + content.update(vim_dict) + + if not serverid: + # convert the key naming in servers + for server in content["servers"]: + metadata = server.pop("metadata", None) + if metadata: + meta_data = [] + self.convertMetadata(metadata, meta_data, True) + server["metadata"] = meta_data + VimDriverUtils.replace_key_by_mapping(server, + self.keys_mapping) + else: + # convert the key naming in the server specified by id + server = content.pop("server", None) + metadata = server.pop("metadata", None) + if metadata: + meta_data = [] + self.convertMetadata(metadata, meta_data, True) + server["metadata"] = meta_data + VimDriverUtils.replace_key_by_mapping(server, + self.keys_mapping) + content.update(server) + + return content, resp.status_code + + def post(self, request, vimid="", tenantid="", serverid=""): + logger.debug("Servers--post::> %s" % request.data) + try: + # check if created already: check name + query = "name=%s" % request.data["name"] + content, status_code = self.get_servers(query, vimid, tenantid) + existed = False + if status_code == 200: + for server in content["servers"]: + if server["name"] == request.data["name"]: + existed = True + break + pass + if existed == True and server: + vim_dict = { + "returnCode": 0, + } + server.update(vim_dict) + return Response(data=server, status=status_code) + + # prepare request resource to vim instance + req_resouce = "servers" + + vim = VimDriverUtils.get_vim_info(vimid) + sess = VimDriverUtils.get_session(vim, tenantid) + server = request.data + + # convert parameters + boot = server.pop("boot", None) + if not boot: + return Response(data={'error': "missing boot paramters"}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + if boot["type"] == 1: + # boot from volume + server["block_device_mapping_v2 "] = {"uuid": boot["volumeId"], + "source_type": "volume", + "destination_type": "volume", + "delete_on_termination": "false"} + else: + # boot from image + server["imageRef"] = boot["imageId"] + + nicarray = server.pop("nicArray", None) + if not nicarray: + return Response(data={'error': "missing nicArray paramters"}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + else: + networks = [] + for nic in nicarray: + networks.append({"port": nic["portId"]}) + if len(networks) > 0: + server["networks"] = networks + + meta_data = server.pop("metadata", None) + if meta_data: + metadata = {} + self.convertMetadata(metadata, meta_data, False) + server["metadata"] = metadata + + contextarray = server.pop("contextArray", None) + if contextarray: + # now set "contextArray" array + personalities = [] + for context in contextarray: + personalities.append({"path": context["fileName"], "contents": context["fileData"]}) + if len(personalities) > 0: + server["personality"] = personalities + pass + + volumearray = server.pop("volumeArray", None) + + VimDriverUtils.replace_key_by_mapping(server, + self.keys_mapping, True) + req_body = json.JSONEncoder().encode({"server": server}) + resp = sess.post(req_resouce, data=req_body, + endpoint_filter=self.service, headers={"Content-Type": "application/json", + "Accept": "application/json"}) + + resp_body = resp.json().pop("server", None) + + if resp.status_code == 201 and volumearray: + # server is created, now attach volumes + for volumeId in volumearray: + self.attachVolume(sess, resp_body["id"], volumeId) + pass + + metadata = resp_body.pop("metadata", None) + if metadata: + meta_data = [] + self.convertMetadata(metadata, meta_data, True) + resp_body["metadata"] = meta_data + + VimDriverUtils.replace_key_by_mapping(resp_body, self.keys_mapping) + vim_dict = { + "vimName": vim["name"], + "vimId": vim["vimId"], + "tenantId": tenantid, + "returnCode": 1, + } + resp_body.update(vim_dict) + resp_body["volumeArray"] = volumearray + resp_body["nicArray"] = nicarray + resp_body["contextArray"] = contextarray + return Response(data=resp_body, status=resp.status_code) + except VimDriverNewtonException as e: + return Response(data={'error': e.content}, status=e.status_code) + except Exception as e: + return Response(data={'error': str(e)}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + pass + + def delete(self, request, vimid="", tenantid="", serverid=""): + logger.debug("Servers--delete::> %s" % request.data) + try: + # prepare request resource to vim instance + req_resouce = "servers" + if serverid: + req_resouce += "/%s" % serverid + + vim = VimDriverUtils.get_vim_info(vimid) + sess = VimDriverUtils.get_session(vim, tenantid) + resp = sess.delete(req_resouce, endpoint_filter=self.service) + return Response(status=resp.status_code) + except VimDriverNewtonException as e: + return Response(data={'error': e.content}, status=e.status_code) + except Exception as e: + return Response(data={'error': str(e)}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + pass -- cgit 1.2.3-korg