diff options
-rw-r--r-- | vio/docker/Dockerfile | 2 | ||||
-rwxr-xr-x | vio/run.sh | 4 | ||||
-rw-r--r-- | vio/vio/api_v2/api_definition/ports.yaml | 83 | ||||
-rw-r--r-- | vio/vio/api_v2/api_definition/subnets.yaml | 88 | ||||
-rw-r--r-- | vio/vio/api_v2/api_router/controller_builder.py | 77 | ||||
-rw-r--r-- | vio/vio/api_v2/service.py | 4 | ||||
-rwxr-xr-x | vio/vio/event_listener/.gitignore | 1 | ||||
-rwxr-xr-x | vio/vio/event_listener/__init__.py | 13 | ||||
-rwxr-xr-x | vio/vio/event_listener/i18n.py | 27 | ||||
-rwxr-xr-x | vio/vio/event_listener/listener.conf | 3 | ||||
-rwxr-xr-x | vio/vio/event_listener/server.py | 113 | ||||
-rw-r--r-- | vio/vio/pub/config/config.py | 7 | ||||
-rw-r--r-- | vio/vio/scripts/api.py | 4 |
13 files changed, 391 insertions, 35 deletions
diff --git a/vio/docker/Dockerfile b/vio/docker/Dockerfile index 3879b1c..9c67741 100644 --- a/vio/docker/Dockerfile +++ b/vio/docker/Dockerfile @@ -7,6 +7,8 @@ ENV AAI_PORT "8443" ENV AAI_SCHEMA_VERSION "v11" ENV AAI_USERNAME "AAI" ENV AAI_PASSWORD "AAI" +ENV MR_ADDR “127.0.0.1” +ENV MR_PORT “3904” EXPOSE 9004 @@ -20,12 +20,14 @@ sed -i "s/AAI_PORT =.*/AAI_PORT = \"${AAI_PORT}\"/g" vio/pub/config/config.py sed -i "s/AAI_SCHEMA_VERSION =.*/AAI_SCHEMA_VERSION = \"${AAI_SCHEMA_VERSION}\"/g" vio/pub/config/config.py sed -i "s/AAI_USERNAME =.*/AAI_USERNAME = \"${AAI_USERNAME}\"/g" vio/pub/config/config.py sed -i "s/AAI_PASSWORD =.*/AAI_PASSWORD = \"${AAI_PASSWORD}\"/g" vio/pub/config/config.py - +sed -i "s/MR_ADDR =.*/MR_ADDR = \"${MR_ADDR}\"/g" vio/pub/config/config.py +sed -i "s/MR_PORT =.*/MR_PORT = \"${MR_PORT}\"/g" vio/pub/config/config.py logDir="/var/log/onap/multicloud/vio" nohup python manage.py runserver 0.0.0.0:9004 2>&1 & +nohup python vio/event_listener/server.py 2>&1 & while [ ! -f $logDir/vio.log ]; do sleep 1 diff --git a/vio/vio/api_v2/api_definition/ports.yaml b/vio/vio/api_v2/api_definition/ports.yaml new file mode 100644 index 0000000..0599ae2 --- /dev/null +++ b/vio/vio/api_v2/api_definition/ports.yaml @@ -0,0 +1,83 @@ +--- + info: + version: "1.0.0" + title: "Multi Cloud Port" + description: "Definition of Port API" + termsOfService: "http://swagger.io/terms/" + schemes: + - "http" + produces: + - "application/json" + paths: + /{vimid}/{tenantid}/ports/{portid}: + parameters: + - type: string + name: vimid + - type: string + format: uuid + name: tenantid + - type: string + name: portid + in: path + required: true + get: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/port" + get_all: + produces: + - "application/json" + responses: + "200": + schema: + type: "array" + items: + $ref: "#/definitions/port" + post: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/port" + delete: + responses: "204" + vim_path: "/network/v2.0/ports" + definitions: + port: + plural_vim_resource: "ports" + vim_resource: "port" + plural: "port" + properties: + name: + type: string + required: true + source: port.name + id: + type: string + source: port.id + status: + type: string + source: port.status + networkId: + type: string + source: port.network_id + required: true + vnicType: + source: port.binding:vnic_type + securityGroups: + type: string + source: port.security_groups + tenantId: + type: string + source: port.tenant_id + macAddress: + type: string + source: port.mac_address + subnetId: + source: port.fixed_ips[0].subnet_id + ip: + source: port.fixed_ips[0].ip_address diff --git a/vio/vio/api_v2/api_definition/subnets.yaml b/vio/vio/api_v2/api_definition/subnets.yaml new file mode 100644 index 0000000..bbe35c0 --- /dev/null +++ b/vio/vio/api_v2/api_definition/subnets.yaml @@ -0,0 +1,88 @@ +--- + info: + version: "1.0.0" + title: "Multi Cloud Subnet" + description: "Definition of Subnet API" + termsOfService: "http://swagger.io/terms/" + schemes: + - "http" + produces: + - "application/json" + paths: + /{vimid}/{tenantid}/subnets/{subnetid}: + parameters: + - type: string + name: vimid + - type: string + format: uuid + name: tenantid + - type: string + name: subnetid + in: path + required: true + get: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/subnet" + get_all: + produces: + - "application/json" + responses: + "200": + schema: + type: "array" + items: + $ref: "#/definitions/subnet" + post: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/subnet" + delete: + responses: "204" + vim_path: "/network/v2.0/subnets" + definitions: + subnet: + plural_vim_resource: "subnets" + vim_resource: "subnet" + plural: "subnets" + properties: + name: + type: string + required: true + source: subnet.name + id: + type: string + source: subnet.id + status: + type: string + source: subnet.status + networkId: + type: string + source: subnet.network_id + required: true + allocationPools: + source: subnet.allocation_pools + gatewayIp: + type: string + source: subnet.gateway_ip + default: None + tenantId: + type: string + source: subnet.tenant_id + enableDhcp: + type: boolean + source: subnet.enable_dhcp + ipVersion: + source: subnet.ip_version + dnsNameServers: + source: subnet.dns_nameservers + cidr: + source: subnet.cidr + hostRoutes: + source: subnet.host_routes diff --git a/vio/vio/api_v2/api_router/controller_builder.py b/vio/vio/api_v2/api_router/controller_builder.py index 4e6d39d..a3c70b2 100644 --- a/vio/vio/api_v2/api_router/controller_builder.py +++ b/vio/vio/api_v2/api_router/controller_builder.py @@ -16,12 +16,16 @@ from keystoneauth1.identity import v3 as keystone_v3 from keystoneauth1 import session import pecan from pecan import rest +import re from vio.api_v2.api_definition import utils from vio.pub import exceptions from vio.pub.msapi import extsys +OBJ_IN_ARRAY = "(\w+)\[(\d+)\]\.(\w+)" + + def _get_vim_auth_session(vim_id, tenant_id): """ Get the auth session to backend VIM """ @@ -67,48 +71,56 @@ def _convert_default_value(default): return default +def _property_exists(resource, attr, required=False): + if attr not in resource: + if required: + raise Exception("Required field %s is missed in VIM " + "resource %s", (attr, resource)) + else: + return False + + return True + + def _convert_vim_res_to_mc_res(vim_resource, res_properties): mc_resource = {} for key in res_properties: - vim_res, attr = res_properties[key]["source"].split('.') - - if attr not in vim_resource[vim_res]: - if res_properties[key].get("required"): - raise Exception("Required field %s is missed in VIM " - "resource %s", (attr, vim_resource)) + vim_res, attr = res_properties[key]["source"].split('.', 1) + # action = res_properties[key].get("action", "copy") + if re.match(OBJ_IN_ARRAY, attr): + attr, index, sub_attr = re.match(OBJ_IN_ARRAY, attr).groups() + if _property_exists(vim_resource[vim_res], attr): + mc_resource[key] = ( + vim_resource[vim_res][attr][int(index)][sub_attr]) + else: + if _property_exists(vim_resource[vim_res], attr, + res_properties[key].get("required")): + mc_resource[key] = vim_resource[vim_res][attr] else: if "default" in res_properties[key]: mc_resource[key] = _convert_default_value( res_properties[key]["default"]) - # None required fields missed, just skip. - continue - - action = res_properties[key].get("action", "copy") - # TODO(xiaohhui): Actions should be in constants. - if action == "copy": - mc_resource[key] = vim_resource[vim_res][attr] - return mc_resource def _convert_mc_res_to_vim_res(mc_resource, res_properties): vim_resource = {} for key in res_properties: - vim_res, attr = res_properties[key]["source"].split('.') - - if key not in mc_resource: - if res_properties[key].get("required"): - raise Exception("Required field %s is missed in MultiCloud " - "resource %s", (key, mc_resource)) - else: - # None required fields missed, just skip. - continue - - action = res_properties[key].get("action", "copy") - # TODO(xiaohhui): Actions should be in constants. - if action == "copy": - vim_resource[attr] = mc_resource[key] + vim_res, attr = res_properties[key]["source"].split('.', 1) + # action = res_properties[key].get("action", "copy") + if re.match(OBJ_IN_ARRAY, attr): + attr, index, sub_attr = re.match(OBJ_IN_ARRAY, attr).groups() + if _property_exists(mc_resource, key): + vim_resource[attr] = vim_resource.get(attr, []) + if vim_resource[attr]: + vim_resource[attr][0].update({sub_attr: mc_resource[key]}) + else: + vim_resource[attr].append({sub_attr: mc_resource[key]}) + else: + if _property_exists(mc_resource, key, + res_properties[key].get("required")): + vim_resource[attr] = mc_resource[key] return vim_resource @@ -141,10 +153,11 @@ def _build_api_controller(api_meta): resp = session.get(full_url, endpoint_filter=service) mc_res = _convert_vim_res_to_mc_res(resp.json(), resource_properties) - return {"vimName": vim_id, - name: mc_res, - "tenantId": tenant_id, - "vimid": vim_id} + mc_res.update({"vimName": vim_id, + "vimId": vim_id, + "tenantId": tenant_id, + "returnCode": 0}) + return mc_res controller_meta["get"] = _get diff --git a/vio/vio/api_v2/service.py b/vio/vio/api_v2/service.py index a9473c3..60fb991 100644 --- a/vio/vio/api_v2/service.py +++ b/vio/vio/api_v2/service.py @@ -16,6 +16,7 @@ from oslo_service import service from oslo_service import wsgi from vio.api_v2 import app +from vio.pub.config import config as mc_cfg CONF = cfg.CONF @@ -33,9 +34,8 @@ class WSGIService(service.ServiceBase): CONF, "vio", self.app, - # TODO(xiaohhui): these should be configurable. host="0.0.0.0", - port="9004", + port=mc_cfg.API_SERVER_PORT, use_ssl=False ) diff --git a/vio/vio/event_listener/.gitignore b/vio/vio/event_listener/.gitignore new file mode 100755 index 0000000..0d20b64 --- /dev/null +++ b/vio/vio/event_listener/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/vio/vio/event_listener/__init__.py b/vio/vio/event_listener/__init__.py new file mode 100755 index 0000000..012fba8 --- /dev/null +++ b/vio/vio/event_listener/__init__.py @@ -0,0 +1,13 @@ +#!/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. diff --git a/vio/vio/event_listener/i18n.py b/vio/vio/event_listener/i18n.py new file mode 100755 index 0000000..772f4cd --- /dev/null +++ b/vio/vio/event_listener/i18n.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import oslo_i18n + +DOMAIN = "test_oslo" + +_translators = oslo_i18n.TranslatorFactory(domain=DOMAIN) + +# The primary translation function using the well-known name "_" +_ = _translators.primary + +# The contextual translation function using the name "_C" +_C = _translators.contextual_form + +# The plural translation function using the name "_P" +_P = _translators.plural_form + +# Translators for log levels. +# +# The abbreviated names are meant to reflect the usual use of a short +# name like '_'. The "L" is for "log" and the other letter comes from +# the level. +_LI = _translators.log_info +_LW = _translators.log_warning +_LE = _translators.log_error +_LC = _translators.log_critical diff --git a/vio/vio/event_listener/listener.conf b/vio/vio/event_listener/listener.conf new file mode 100755 index 0000000..e57614f --- /dev/null +++ b/vio/vio/event_listener/listener.conf @@ -0,0 +1,3 @@ +[Listener] +rabbit_ip=10.154.9.172 +rabbit_passwd=6C2B96AsbinmFf1a9c6a
\ No newline at end of file diff --git a/vio/vio/event_listener/server.py b/vio/vio/event_listener/server.py new file mode 100755 index 0000000..83b9e6f --- /dev/null +++ b/vio/vio/event_listener/server.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from oslo_config import cfg +from oslo_log import log as logging +from i18n import _LI +import oslo_messaging +import ConfigParser +import json +import os +import requests +from vio.pub.config.config import MR_ADDR +from vio.pub.config.config import MR_PORT + +LOG = logging.getLogger(__name__) + + +def prepare(): + + product_name = "oslo_server" + logging.register_options(cfg.CONF) + logging.setup(cfg.CONF, product_name) + + +''' +below items must be added into vio nova.conf then restart nova services: +notification_driver=messaging +notification_topics= notifications_test +notify_on_state_change=vm_and_task_state +notify_on_any_change=True +instance_usage_audit=True +instance_usage_audit_period=hour +''' + + +def getConfig(section, key): + + config = ConfigParser.ConfigParser() + path = os.path.split(os.path.realpath(__file__))[0] + '/listener.conf' + config.read(path) + return config.get(section, key) + + +class NotificationEndPoint(): + + filter_rule = oslo_messaging.NotificationFilter( + publisher_id='^compute.*') + + def info(self, ctxt, publisher_id, event_type, payload, metadata): + + VM_EVENTS = { + 'compute.instance.unpause.start', + 'compute.instance.pause.start', + 'compute.instance.power_off.start', + 'compute.instance.reboot.start', + 'compute.instance.create.start' + } + + status = payload.get('state_description') + if status != '' and event_type in VM_EVENTS: + url = 'http://%s:%s/events/test' % (MR_ADDR, MR_PORT) + headers = {'Content-type': 'application/json'} + requests.post(url, json.dumps(payload), headers=headers) + + LOG.info(event_type) + self.action(payload) + + def action(self, data): + LOG.info(_LI(json.dumps(data))) + + +class Server(object): + + def __init__(self): + self.topic = 'notifications_test' + self.server = None + prepare() + + +class NotificationServer(Server): + + def __init__(self): + super(NotificationServer, self).__init__() + # rabbit IP and password come from listener.conf + url = 'rabbit://test:%s@%s:5672/' % ( + getConfig('Listener', 'rabbit_passwd'), + getConfig('Listener', 'rabbit_ip') + ) + self.transport = oslo_messaging.get_notification_transport( + cfg.CONF, + url=url) + # The exchange must be the same as + # control_exchange in transport setting in client. + self.targets = [oslo_messaging.Target( + topic=self.topic, + exchange='nova')] + self.endpoints = [NotificationEndPoint()] + + def start(self): + LOG.info(_LI("Start Notification server...")) + self.server = oslo_messaging.get_notification_listener( + self.transport, + self.targets, + self.endpoints, + executor='threading') + self.server.start() + self.server.wait() + + +if __name__ == '__main__': + + notification_server = NotificationServer() + notification_server.start() diff --git a/vio/vio/pub/config/config.py b/vio/vio/pub/config/config.py index 9b4d6c8..757ba28 100644 --- a/vio/vio/pub/config/config.py +++ b/vio/vio/pub/config/config.py @@ -28,7 +28,14 @@ AAI_SCHEMA_VERSION = "v13" AAI_USERNAME = 'AAI' AAI_PASSWORD = 'AAI' +# [DMaaP] +MR_ADDR = "127.0.0.1" +MR_PORT = "3904" + # [MDC] SERVICE_NAME = "multicloud-vio" FORWARDED_FOR_FIELDS = ["HTTP_X_FORWARDED_FOR", "HTTP_X_FORWARDED_HOST", "HTTP_X_FORWARDED_SERVER"] + +# [Local Config] +API_SERVER_PORT = 9004 diff --git a/vio/vio/scripts/api.py b/vio/vio/scripts/api.py index c3bd1a7..5ba83c9 100644 --- a/vio/vio/scripts/api.py +++ b/vio/vio/scripts/api.py @@ -12,9 +12,13 @@ import eventlet eventlet.monkey_patch() +import os # noqa from oslo_config import cfg # noqa from oslo_service import service # noqa import sys # noqa +# FIXME: Since there is no explicitly setup process for the project. Hack the +# python here. +sys.path.append(os.path.abspath('.')) from vio.api_v2 import service as api_service # noqa |