X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2Fvim-emu.git;a=blobdiff_plain;f=src%2Femuvim%2Fapi%2Frest%2Fcompute.py;h=62a8f18e28bca14f2d4325ed1c4c7b0ea7dcafe4;hp=8d46aa2fa1a4f02025e45abb0b925a69ea26fdb3;hb=0719f4efe35a1ef06fe2751228e63d38b855967c;hpb=139b0bee04cd9336bcd7acb6728d0cf6976d6f5d diff --git a/src/emuvim/api/rest/compute.py b/src/emuvim/api/rest/compute.py index 8d46aa2..62a8f18 100755 --- a/src/emuvim/api/rest/compute.py +++ b/src/emuvim/api/rest/compute.py @@ -1,40 +1,39 @@ -""" -Copyright (c) 2015 SONATA-NFV and Paderborn University -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. - -Neither the name of the SONATA-NFV [, ANY ADDITIONAL AFFILIATION] -nor the names of its contributors may be used to endorse or promote -products derived from this software without specific prior written -permission. - -This work has been performed in the framework of the SONATA project, -funded by the European Commission under Grant number 671517 through -the Horizon 2020 and 5G-PPP programmes. The authors would like to -acknowledge the contributions of their colleagues of the SONATA -partner consortium (www.sonata-nfv.eu). -""" +# Copyright (c) 2015 SONATA-NFV and Paderborn University +# 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. +# +# Neither the name of the SONATA-NFV, Paderborn University +# nor the names of its contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# This work has been performed in the framework of the SONATA project, +# funded by the European Commission under Grant number 671517 through +# the Horizon 2020 and 5G-PPP programmes. The authors would like to +# acknowledge the contributions of their colleagues of the SONATA +# partner consortium (www.sonata-nfv.eu). import logging from flask_restful import Resource from flask import request import json -from copy import deepcopy +import threading -logging.basicConfig(level=logging.INFO) +logging.basicConfig() CORS_HEADER = {'Access-Control-Allow-Origin': '*'} +# the dcs dict is set in the rest_api_endpoint.py upon datacenter init dcs = {} @@ -49,6 +48,7 @@ class Compute(Resource): example networks list({"id":"input","ip": "10.0.0.254/8"}, {"id":"output","ip": "11.0.0.254/24"}) :return: docker inspect dict of deployed docker """ + global dcs def put(self, dc_label, compute_name, resource=None, value=None): @@ -58,7 +58,7 @@ class Compute(Resource): data = request.json if data is None: data = {} - elif type(data) is not dict: + elif not isinstance(data, dict): data = json.loads(request.json) network = data.get("network") @@ -67,9 +67,37 @@ class Compute(Resource): command = data.get("docker_command") try: - logging.debug("API CALL: compute start") + if compute_name is None or compute_name == "None": + logging.error("No compute name defined in request.") + return "No compute name defined in request.", 500, CORS_HEADER + if dc_label is None or dcs.get(dc_label) is None: + logging.error("No datacenter defined in request.") + return "No datacenter defined in request.", 500, CORS_HEADER c = dcs.get(dc_label).startCompute( compute_name, image=image, command=command, network=nw_list) + # (if available) trigger emu. entry point given in Dockerfile + try: + config = c.dcinfo.get("Config", dict()) + env = config.get("Env", list()) + legacy_command_execution = False + for env_var in env: + var, cmd = map(str.strip, map(str, env_var.split('=', 1))) + logging.debug("%r = %r" % (var, cmd)) + if var == "SON_EMU_CMD" or var == "VIM_EMU_CMD": + logging.info("Executing script in '{}': {}={}" + .format(compute_name, var, cmd)) + # execute command in new thread to ensure that API is + # not blocked by VNF + t = threading.Thread(target=c.cmdPrint, args=(cmd,)) + t.daemon = True + t.start() + legacy_command_execution = True + break + if not legacy_command_execution: + c.start() + except Exception as ex: + logging.warning("Couldn't run Docker entry point VIM_EMU_CMD") + logging.exception("Exception:") # return docker inspect dict return c.getStatus(), 200, CORS_HEADER except Exception as ex: @@ -81,7 +109,8 @@ class Compute(Resource): logging.debug("API CALL: compute status") try: - return dcs.get(dc_label).containers.get(compute_name).getStatus(), 200, CORS_HEADER + return dcs.get(dc_label).containers.get( + compute_name).getStatus(), 200, CORS_HEADER except Exception as ex: logging.exception("API error.") return ex.message, 500, CORS_HEADER @@ -89,7 +118,8 @@ class Compute(Resource): def delete(self, dc_label, compute_name): logging.debug("API CALL: compute stop") try: - return dcs.get(dc_label).stopCompute(compute_name), 200, CORS_HEADER + return dcs.get(dc_label).stopCompute( + compute_name), 200, CORS_HEADER except Exception as ex: logging.exception("API error.") return ex.message, 500, CORS_HEADER @@ -125,15 +155,19 @@ class ComputeList(Resource): all_containers = [] for dc in dcs.itervalues(): all_containers += dc.listCompute() - return [(c.name, c.getStatus()) for c in all_containers], 200, CORS_HEADER + container_list = [(c.name, c.getStatus()) + for c in all_containers] + return container_list, 200, CORS_HEADER else: # return list of compute nodes for specified DC - return [(c.name, c.getStatus()) - for c in dcs.get(dc_label).listCompute()], 200, CORS_HEADER + container_list = [(c.name, c.getStatus()) + for c in dcs.get(dc_label).listCompute()] + return container_list, 200, CORS_HEADER except Exception as ex: logging.exception("API error.") return ex.message, 500, CORS_HEADER + class ComputeResources(Resource): """ Update the container's resources using the docker.update function @@ -174,8 +208,9 @@ class ComputeResources(Resource): # then no data if params is None: params = {} - logging.debug("REST CALL: update container resources {0}".format(params)) - #check if container exists + logging.debug( + "REST CALL: update container resources {0}".format(params)) + # check if container exists d = dcs.get(dc_label).net.getNodeByName(compute_name) # general request of cpu percentage @@ -185,24 +220,26 @@ class ComputeResources(Resource): cpu_period = int(dcs.get(dc_label).net.cpu_period) value = params.get('cpu_bw') cpu_quota = int(cpu_period * float(value)) - #put default values back + # put default values back if float(value) <= 0: cpu_period = 100000 cpu_quota = -1 params['cpu_period'] = cpu_period params['cpu_quota'] = cpu_quota - #d.updateCpuLimit(cpu_period=cpu_period, cpu_quota=cpu_quota) + # d.updateCpuLimit(cpu_period=cpu_period, cpu_quota=cpu_quota) # only pass allowed keys to docker allowed_keys = ['blkio_weight', 'cpu_period', 'cpu_quota', 'cpu_shares', 'cpuset_cpus', 'cpuset_mems', 'mem_limit', 'mem_reservation', 'memswap_limit', 'kernel_memory', 'restart_policy'] - filtered_params = {key:params[key] for key in allowed_keys if key in params} + filtered_params = {key: params[key] + for key in allowed_keys if key in params} d.update_resources(**filtered_params) return d + class DatacenterList(Resource): global dcs