CORD-60:XOS ONOS model and tosca enhancements to deploy Notifier application in ONOS instances and to perform OSGI component configuration
diff --git a/xos/configurations/cord/cord.yaml b/xos/configurations/cord/cord.yaml
index 8aa4676..06eaf23 100644
--- a/xos/configurations/cord/cord.yaml
+++ b/xos/configurations/cord/cord.yaml
@@ -137,7 +137,21 @@
node: service_volt
relationship: tosca.relationships.UsedByService
properties:
- dependencies: org.onosproject.openflow-base, org.onosproject.olt
+ install_dependencies: onos-ext-notifier-1.0-SNAPSHOT.oar, onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
+ dependencies: org.onosproject.openflow-base, org.onosproject.olt, org.ciena.onos.ext_notifier, org.ciena.onos.volt_event_publisher
+ component_config: >
+ {
+ "org.ciena.onos.ext_notifier.KafkaNotificationBridge":{
+ "rabbit.user": "<rabbit_user>",
+ "rabbit.password": "<rabbit_password>",
+ "rabbit.host": "<rabbit_host>",
+ "publish.rabbit": "true",
+ "volt.events.rabbit.topic": "notifications.info",
+ "volt.events.rabbit.exchange": "voltlistener",
+ "volt.events.opaque.info": "{project_id: <keystone_tenant_id>, user_id: <keystone_user_id>}",
+ "publish.volt.events": "true"
+ }
+ }
# config_network-cfg.json: >
# {
# "devices" : {
diff --git a/xos/core/xoslib/methods/ceilometerview.py b/xos/core/xoslib/methods/ceilometerview.py
index 825cce4..1b46855 100644
--- a/xos/core/xoslib/methods/ceilometerview.py
+++ b/xos/core/xoslib/methods/ceilometerview.py
@@ -468,6 +468,80 @@
'label': '',
'description': _("Number of VCPUs"),
}),
+ ("disk.read.requests", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Number of read requests"),
+ }),
+ ("disk.write.requests", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Number of write requests"),
+ }),
+ ("disk.read.bytes", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Volume of reads"),
+ }),
+ ("disk.write.bytes", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Volume of writes"),
+ }),
+ ("disk.read.requests.rate", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Average rate of read requests"),
+ }),
+ ("disk.write.requests.rate", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Average rate of write requests"),
+ }),
+ ("disk.read.bytes.rate", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Average rate of reads"),
+ }),
+ ("disk.write.bytes.rate", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Average volume of writes"),
+ }),
+ ("disk.root.size", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Size of root disk"),
+ }),
+ ("disk.ephemeral.size", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Size of ephemeral disk"),
+ }),
+ ("network.incoming.bytes", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Number of incoming bytes "
+ "on the network for a VM interface"),
+ }),
+ ("network.outgoing.bytes", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Number of outgoing bytes "
+ "on the network for a VM interface"),
+ }),
+ ("network.incoming.packets", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Number of incoming "
+ "packets for a VM interface"),
+ }),
+ ("network.outgoing.packets", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Number of outgoing "
+ "packets for a VM interface"),
+ }),
("network.incoming.bytes.rate", {
'type': _("Nova"),
'label': '',
@@ -480,6 +554,18 @@
'description': _("Average rate per sec of outgoing "
"bytes on a VM network interface"),
}),
+ ("network.incoming.packets.rate", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Average rate per sec of incoming "
+ "packets on a VM network interface"),
+ }),
+ ("network.outgoing.packets.rate", {
+ 'type': _("Nova"),
+ 'label': '',
+ 'description': _("Average rate per sec of outgoing "
+ "packets on a VM network interface"),
+ }),
])
# Adding flavor based meters into meters_info dict
# TODO(lsmola) this kind of meter will be probably deprecated
@@ -512,21 +598,76 @@
'label': '',
'description': _("Existence of network"),
}),
+ ('network.create', {
+ 'type': _("Neutron"),
+ 'label': '',
+ 'description': _("Creation requests for this network"),
+ }),
+ ('network.update', {
+ 'type': _("Neutron"),
+ 'label': '',
+ 'description': _("Update requests for this network"),
+ }),
('subnet', {
'type': _("Neutron"),
'label': '',
'description': _("Existence of subnet"),
}),
+ ('subnet.create', {
+ 'type': _("Neutron"),
+ 'label': '',
+ 'description': _("Creation requests for this subnet"),
+ }),
+ ('subnet.update', {
+ 'type': _("Neutron"),
+ 'label': '',
+ 'description': _("Update requests for this subnet"),
+ }),
('port', {
'type': _("Neutron"),
'label': '',
'description': _("Existence of port"),
}),
+ ('port.create', {
+ 'type': _("Neutron"),
+ 'label': '',
+ 'description': _("Creation requests for this port"),
+ }),
+ ('port.update', {
+ 'type': _("Neutron"),
+ 'label': '',
+ 'description': _("Update requests for this port"),
+ }),
+ ('router', {
+ 'type': _("Neutron"),
+ 'label': '',
+ 'description': _("Existence of router"),
+ }),
+ ('router.create', {
+ 'type': _("Neutron"),
+ 'label': '',
+ 'description': _("Creation requests for this router"),
+ }),
+ ('router.update', {
+ 'type': _("Neutron"),
+ 'label': '',
+ 'description': _("Update requests for this router"),
+ }),
('ip.floating', {
'type': _("Neutron"),
'label': '',
'description': _("Existence of floating ip"),
}),
+ ('ip.floating.create', {
+ 'type': _("Neutron"),
+ 'label': '',
+ 'description': _("Creation requests for this floating ip"),
+ }),
+ ('ip.floating.update', {
+ 'type': _("Neutron"),
+ 'label': '',
+ 'description': _("Update requests for this floating ip"),
+ }),
])
def _get_glance_meters_info(self):
diff --git a/xos/observers/onos/onos-ext-notifier-1.0-SNAPSHOT.oar b/xos/observers/onos/onos-ext-notifier-1.0-SNAPSHOT.oar
new file mode 100644
index 0000000..893c01a
--- /dev/null
+++ b/xos/observers/onos/onos-ext-notifier-1.0-SNAPSHOT.oar
Binary files differ
diff --git a/xos/observers/onos/onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar b/xos/observers/onos/onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
new file mode 100644
index 0000000..7a32268
--- /dev/null
+++ b/xos/observers/onos/onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
Binary files differ
diff --git a/xos/services/onos/models.py b/xos/services/onos/models.py
index 80e903e..1e869d1 100644
--- a/xos/services/onos/models.py
+++ b/xos/services/onos/models.py
@@ -38,6 +38,7 @@
KIND = ONOS_KIND
default_attributes = {"name": "",
+ "install_dependencies": "",
"dependencies": ""}
def __init__(self, *args, **kwargs):
onos_services = ONOSService.get_service_objects().all()
@@ -84,6 +85,14 @@
def dependencies(self, value):
self.set_attribute("dependencies", value)
+ @property
+ def install_dependencies(self):
+ return self.get_attribute("install_dependencies", self.default_attributes["install_dependencies"])
+
+ @install_dependencies.setter
+ def install_dependencies(self, value):
+ self.set_attribute("install_dependencies", value)
+
#@property
#def instance(self):
# instance_id = self.get_attribute("instance_id", self.default_attributes["instance_id"])
diff --git a/xos/synchronizers/onos/steps/sync_onosapp.py b/xos/synchronizers/onos/steps/sync_onosapp.py
index 91eec44..c7b429b 100644
--- a/xos/synchronizers/onos/steps/sync_onosapp.py
+++ b/xos/synchronizers/onos/steps/sync_onosapp.py
@@ -5,12 +5,14 @@
import sys
import base64
import time
+import re
+import json
from django.db.models import F, Q
from xos.config import Config
from synchronizers.base.syncstep import SyncStep
from synchronizers.base.ansible import run_template_ssh
from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
-from core.models import Service, Slice
+from core.models import Service, Slice, ControllerSlice, ControllerUser
from services.onos.models import ONOSService, ONOSApp
from xos.logger import Logger, logging
@@ -86,10 +88,31 @@
result = result + '], "ipPrefix": "%s"}' % ipPrefix
return result
+ def get_dynamic_parameter_value(self, o, param):
+ instance = self.get_instance(o)
+ if not instance:
+ raise "No instance for ONOS App"
+ if param == 'rabbit_host':
+ return instance.controller.rabbit_host
+ if param == 'rabbit_user':
+ return instance.controller.rabbit_user
+ if param == 'rabbit_password':
+ return instance.controller.rabbit_password
+ if param == 'keystone_tenant_id':
+ cslice = ControllerSlice.objects.get(slice=instance.slice)
+ if not cslice:
+ raise Exception("Controller slice object for %s does not exist" % instance.slice.name)
+ return cslice.tenant_id
+ if param == 'keystone_user_id':
+ cuser = ControllerUser.objects.get(user=instance.creator)
+ if not cuser:
+ raise Exception("Controller user object for %s does not exist" % instance.creator)
+ return cuser.kuser_id
def write_configs(self, o):
o.config_fns = []
o.rest_configs = []
+ o.component_configs = []
o.files_dir = self.get_files_dir(o)
if not os.path.exists(o.files_dir):
@@ -131,6 +154,20 @@
# later.
file(os.path.join(o.files_dir, fn),"w").write(" " +value)
o.rest_configs.append( {"endpoint": endpoint, "fn": fn} )
+ if name.startswith("component_config"):
+ components = json.loads(value)
+ for component in components.keys():
+ config = components[component]
+ for key in config.keys():
+ config_val = config[key]
+ found = re.findall('<(.+?)>',config_val)
+ for x in found:
+ #Get value corresponding to that string
+ val = self.get_dynamic_parameter_value(o, x)
+ if val:
+ config_val = re.sub('<'+x+'>', val, config_val)
+ #TODO: else raise an exception?
+ o.component_configs.append( {"component": component, "config_params": "'{\""+key+"\":\""+config_val+"\"}'"} )
def prepare_record(self, o):
self.write_configs(o)
@@ -145,11 +182,17 @@
fields["config_fns"] = o.config_fns
fields["rest_configs"] = o.rest_configs
fields["early_rest_configs"] = o.early_rest_configs
+ fields["component_configs"] = o.component_configs
if o.dependencies:
fields["dependencies"] = [x.strip() for x in o.dependencies.split(",")]
else:
fields["dependencies"] = []
+ if o.install_dependencies:
+ fields["install_dependencies"] = [x.strip() for x in o.install_dependencies.split(",")]
+ else:
+ fields["install_dependencies"] = []
+
if (instance.isolation=="container"):
fields["ONOS_container"] = "%s-%s" % (instance.slice.name, str(instance.id))
else:
diff --git a/xos/synchronizers/onos/steps/sync_onosapp.yaml b/xos/synchronizers/onos/steps/sync_onosapp.yaml
index a03368b..5373f9d 100644
--- a/xos/synchronizers/onos/steps/sync_onosapp.yaml
+++ b/xos/synchronizers/onos/steps/sync_onosapp.yaml
@@ -7,6 +7,13 @@
vars:
appname: {{ appname }}
dependencies: {{ dependencies }}
+{% if component_configs %}
+ component_configs:
+{% for component_config in component_configs %}
+ - component: {{ component_config.component }}
+ config_params: {{ component_config.config_params }}
+{% endfor %}
+{% endif %}
{% if rest_configs %}
rest_configs:
{% for rest_config in rest_configs %}
@@ -86,6 +93,30 @@
wait_for: timeout=15
{% endif %}
+{% if install_dependencies %}
+ - name: Install app file directory
+ file:
+ path=/home/ubuntu/{{ appname }}/apps/
+ state=directory
+
+ - name: Copy over app install files to ONOS host
+ copy:
+ src=/opt/xos/observers/onos/{{ '{{' }} item {{ '}}' }}
+ dest=/home/ubuntu/{{ appname }}/apps/{{ '{{' }} item {{ '}}' }}
+ with_items:
+ {% for install_app in install_dependencies %}
+ - {{ install_app }}
+ {% endfor %}
+
+ - name: POST onos-app install command
+ command: >
+ curl -XPOST -HContent-Type:application/octet-stream -u karaf:karaf --data-binary @/home/ubuntu/{{ appname }}/apps/{{ '{{' }} item {{ '}}' }} http://{{ '{{' }} onosaddr.stdout {{ '}}' }}:8181/onos/v1/applications
+ with_items:
+ {% for dependency in install_dependencies %}
+ - {{ dependency }}
+ {% endfor %}
+{% endif %}
+
{% if dependencies %}
- name: Add dependencies to ONOS
uri:
@@ -99,6 +130,23 @@
{% endfor %}
{% endif %}
+{% if component_configs %}
+ - name: Add ONOS component configuration values
+ command: >
+ curl -XPOST -HContent-Type:application/json -u karaf:karaf -d {{ '{{' }} item.config_params | to_json {{ '}}' }} http://{{ '{{' }} onosaddr.stdout {{ '}}' }}:8181/onos/v1/configuration/{{
+ '{{' }} item.component {{ '}}' }}
+ with_items: "component_configs"
+
+# uri:
+# url: http://{{ '{{' }} onosaddr.stdout {{ '}}' }}:8181/onos/v1/configuration/{{ '{{' }} item.component {{ '}}' }} #http://localhost:8181/onos/v1/configuration/
+# body: "{{ '{{' }} item.config_params | to_json {{ '}}' }}"
+# body_format: json
+# method: POST
+# user: karaf
+# password: karaf
+# with_items: "component_configs"
+{% endif %}
+
{% if rest_configs %}
# Do this after services have been activated, or it will cause an exception.
# vOLT will re-read its net config; vbng may not.
diff --git a/xos/tosca/custom_types/xos.m4 b/xos/tosca/custom_types/xos.m4
index 30798d5..39e4d99 100644
--- a/xos/tosca/custom_types/xos.m4
+++ b/xos/tosca/custom_types/xos.m4
@@ -140,6 +140,12 @@
dependencies:
type: string
required: false
+ install_dependencies:
+ type: string
+ required: false
+ component_config:
+ type: string
+ required: false
config_addresses.json:
type: string
required: false
@@ -159,6 +165,12 @@
dependencies:
type: string
required: false
+ install_dependencies:
+ type: string
+ required: false
+ component_config:
+ type: string
+ required: false
config_network-cfg.json:
type: string
required: false
diff --git a/xos/tosca/custom_types/xos.yaml b/xos/tosca/custom_types/xos.yaml
index 63d7395..613db70 100644
--- a/xos/tosca/custom_types/xos.yaml
+++ b/xos/tosca/custom_types/xos.yaml
@@ -145,6 +145,12 @@
dependencies:
type: string
required: false
+ install_dependencies:
+ type: string
+ required: false
+ component_config:
+ type: string
+ required: false
tosca.nodes.ONOSvBNGApp:
derived_from: tosca.nodes.Root
@@ -162,6 +168,12 @@
dependencies:
type: string
required: false
+ install_dependencies:
+ type: string
+ required: false
+ component_config:
+ type: string
+ required: false
config_addresses.json:
type: string
required: false
@@ -188,6 +200,12 @@
dependencies:
type: string
required: false
+ install_dependencies:
+ type: string
+ required: false
+ component_config:
+ type: string
+ required: false
config_network-cfg.json:
type: string
required: false
diff --git a/xos/tosca/resources/onosapp.py b/xos/tosca/resources/onosapp.py
index 42cb0bf..5947400 100644
--- a/xos/tosca/resources/onosapp.py
+++ b/xos/tosca/resources/onosapp.py
@@ -14,7 +14,7 @@
class XOSONOSApp(XOSResource):
provides = ["tosca.nodes.ONOSApp", "tosca.nodes.ONOSvBNGApp", "tosca.nodes.ONOSvOLTApp", "tosca.nodes.ONOSVTNApp"]
xos_model = ONOSApp
- copyin_props = ["service_specific_id", "dependencies"]
+ copyin_props = ["service_specific_id", "dependencies", "install_dependencies"]
def get_xos_args(self, throw_exception=True):
args = super(XOSONOSApp, self).get_xos_args()
@@ -59,6 +59,8 @@
self.set_tenant_attr(obj, k, v)
elif k.startswith("rest_"):
self.set_tenant_attr(obj, k, v)
+ elif k.startswith("component_config"):
+ self.set_tenant_attr(obj, k, v)
def can_delete(self, obj):
return super(XOSONOSApp, self).can_delete(obj)