Merge branch 'master' of github.com:open-cloud/xos
diff --git a/xos/configurations/cord/cord.yaml b/xos/configurations/cord/cord.yaml
index 02137ec..ea1425a 100644
--- a/xos/configurations/cord/cord.yaml
+++ b/xos/configurations/cord/cord.yaml
@@ -108,6 +108,21 @@
kind: onos
view_url: /admin/onos/onosservice/$id$/
public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+# rest_onos/v1/network/configuration/: >
+# {
+# "devices" : {
+# "of:0000000000000001" : {
+# "accessDevice" : {
+# "uplink" : "2",
+# "vlan" : "222",
+# "defaultVlan" : "1"
+# },
+# "basic" : {
+# "driver" : "default"
+# }
+# }
+# }
+# }
artifacts:
pubkey: /opt/xos/observers/onos/onos_key.pub
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
index ba54a33..953ea97 100644
--- a/xos/core/models/service.py
+++ b/xos/core/models/service.py
@@ -83,6 +83,13 @@
service_ids = [sp.slice.id for sp in ServicePrivilege.objects.filter(user=user)]
return cls.objects.filter(id__in=service_ids)
+ @property
+ def serviceattribute_dict(self):
+ attrs = {}
+ for attr in self.serviceattributes.all():
+ attrs[attr.name] = attr.value
+ return attrs
+
def __unicode__(self): return u'%s' % (self.name)
def can_update(self, user):
@@ -162,7 +169,7 @@
# print "add instance", s
class ServiceAttribute(PlCoreBase):
- name = models.SlugField(help_text="Attribute Name", max_length=128)
+ name = models.CharField(help_text="Attribute Name", max_length=128)
value = StrippedCharField(help_text="Attribute Value", max_length=1024)
service = models.ForeignKey(Service, related_name='serviceattributes', help_text="The Service this attribute is associated with")
@@ -310,6 +317,13 @@
def get_deleted_tenant_objects(cls):
return cls.deleted_objects.filter(kind = cls.KIND)
+ @property
+ def tenantattribute_dict(self):
+ attrs = {}
+ for attr in self.tenantattributes.all():
+ attrs[attr.name] = attr.value
+ return attrs
+
# helper function to be used in subclasses that want to ensure service_specific_id is unique
def validate_unique_service_specific_id(self):
if self.pk is None:
@@ -361,6 +375,7 @@
def pick(self):
from core.models import Node
nodes = list(Node.objects.all())
+
# TODO: logic to filter nodes by which nodes are up, and which
# nodes the slice can instantiate on.
nodes = sorted(nodes, key=lambda node: node.instances.all().count())
diff --git a/xos/observers/onos/steps/sync_onosapp.py b/xos/observers/onos/steps/sync_onosapp.py
index 9b32298..97bb8a6 100644
--- a/xos/observers/onos/steps/sync_onosapp.py
+++ b/xos/observers/onos/steps/sync_onosapp.py
@@ -81,20 +81,25 @@
if not os.path.exists(o.files_dir):
os.makedirs(o.files_dir)
- for attr in o.tenantattributes.all():
- if attr.name.startswith("config_"):
- fn = attr.name[7:] # .replace("_json",".json")
+ # Combine the service attributes with the tenant attributes. Tenant
+ # attribute can override service attributes.
+ attrs = o.provider_service.serviceattribute_dict
+ attrs.update(o.tenantattribute_dict)
+
+ for (name, value) in attrs.items():
+ if name.startswith("config_"):
+ fn = name[7:] # .replace("_json",".json")
o.config_fns.append(fn)
- file(os.path.join(o.files_dir, fn),"w").write(attr.value)
- if attr.name.startswith("rest_"):
- fn = attr.name[5:].replace("/","_")
- endpoint = attr.name[5:]
+ file(os.path.join(o.files_dir, fn),"w").write(value)
+ if name.startswith("rest_"):
+ fn = name[5:].replace("/","_")
+ endpoint = name[5:]
# Ansible goes out of it's way to make our life difficult. If
# 'lookup' sees a file that it thinks contains json, then it'll
# insist on parsing and return a json object. We just want
# a string, so prepend a space and then strip the space off
# later.
- file(os.path.join(o.files_dir, fn),"w").write(" " +attr.value)
+ file(os.path.join(o.files_dir, fn),"w").write(" " +value)
o.rest_configs.append( {"endpoint": endpoint, "fn": fn} )
def prepare_record(self, o):
diff --git a/xos/observers/onos/steps/sync_onosapp.yaml b/xos/observers/onos/steps/sync_onosapp.yaml
index 9ee2513..9105a2e 100644
--- a/xos/observers/onos/steps/sync_onosapp.yaml
+++ b/xos/observers/onos/steps/sync_onosapp.yaml
@@ -45,18 +45,6 @@
{% endfor %}
{% endif %}
-{% if rest_configs %}
- - name: Add ONOS configuration values
- uri:
- url: http://localhost:8181/{{ '{{' }} item.endpoint {{ '}}' }} #http://localhost:8181/onos/v1/network/configuration/
- body: "{{ '{{' }} item.body {{ '}}' }}"
- body_format: raw
- method: POST
- user: karaf
- password: karaf
- with_items: "rest_configs"
-{% endif %}
-
# Don't know how to check for this condition, just wait
- name: Wait for ONOS to install the apps
wait_for: timeout=15
@@ -71,3 +59,17 @@
{% for dependency in dependencies %}
- {{ dependency }}
{% endfor %}
+
+{% 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.
+ - name: Add ONOS configuration values
+ uri:
+ url: http://localhost:8181/{{ '{{' }} item.endpoint {{ '}}' }} #http://localhost:8181/onos/v1/network/configuration/
+ body: "{{ '{{' }} item.body {{ '}}' }}"
+ body_format: raw
+ method: POST
+ user: karaf
+ password: karaf
+ with_items: "rest_configs"
+{% endif %}
diff --git a/xos/tosca/custom_types/xos.m4 b/xos/tosca/custom_types/xos.m4
index d4e96ce..a806327 100644
--- a/xos/tosca/custom_types/xos.m4
+++ b/xos/tosca/custom_types/xos.m4
@@ -101,6 +101,10 @@
xos_base_service_caps
properties:
xos_base_service_props
+ rest_onos/v1/network/configuration/:
+ type: string
+ required: false
+
tosca.nodes.ONOSApp:
derived_from: tosca.nodes.Root
diff --git a/xos/tosca/custom_types/xos.yaml b/xos/tosca/custom_types/xos.yaml
index 0c20211..3339fdf 100644
--- a/xos/tosca/custom_types/xos.yaml
+++ b/xos/tosca/custom_types/xos.yaml
@@ -102,6 +102,10 @@
type: string
required: false
description: Version number of Service.
+ rest_onos/v1/network/configuration/:
+ type: string
+ required: false
+
tosca.nodes.ONOSApp:
derived_from: tosca.nodes.Root
diff --git a/xos/tosca/resources/onosservice.py b/xos/tosca/resources/onosservice.py
index 1275fab..b742ebb 100644
--- a/xos/tosca/resources/onosservice.py
+++ b/xos/tosca/resources/onosservice.py
@@ -5,6 +5,7 @@
sys.path.append("/opt/tosca")
from translator.toscalib.tosca_template import ToscaTemplate
+from core.models import ServiceAttribute
from services.onos.models import ONOSService
from service import XOSService
@@ -14,3 +15,27 @@
xos_model = ONOSService
copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "versionNumber"]
+ def set_service_attr(self, obj, prop_name, value):
+ value = self.try_intrinsic_function(value)
+ if value:
+ attrs = ServiceAttribute.objects.filter(service=obj, name=prop_name)
+ if attrs:
+ attr = attrs[0]
+ if attr.value != value:
+ self.info("updating attribute %s" % prop_name)
+ attr.value = value
+ attr.save()
+ else:
+ self.info("adding attribute %s" % prop_name)
+ ta = ServiceAttribute(service=obj, name=prop_name, value=value)
+ ta.save()
+
+ def postprocess(self, obj):
+ props = self.nodetemplate.get_properties()
+ for (k,d) in props.items():
+ v = d.value
+ if k.startswith("config_"):
+ self.set_service_attr(obj, k, v)
+ elif k.startswith("rest_"):
+ self.set_service_attr(obj, k, v)
+