Merge branch 'master' of github.com:open-cloud/xos
diff --git a/views/ngXosViews/diagnostic/mocks/data/cordsubscriber.json b/views/ngXosViews/diagnostic/mocks/data/cordsubscriber.json
index e2409a7..9f5919a 100644
--- a/views/ngXosViews/diagnostic/mocks/data/cordsubscriber.json
+++ b/views/ngXosViews/diagnostic/mocks/data/cordsubscriber.json
@@ -3,7 +3,6 @@
"humanReadableName": "cordSubscriber-1",
"id": 1,
"service_specific_id": "123",
- "vlan_id": "432",
"s_tag": "222",
"c_tag": "432",
"vcpe_id": 4,
diff --git a/xos/configurations/cord-pod/Makefile b/xos/configurations/cord-pod/Makefile
index 878797c..6d5ddac 100644
--- a/xos/configurations/cord-pod/Makefile
+++ b/xos/configurations/cord-pod/Makefile
@@ -18,6 +18,7 @@
cord: vsg_custom_images
sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/mgmt-net.yaml
sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/cord-vtn-vsg.yaml
+ sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/cord-volt-devices.yaml
exampleservice:
sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/pod-exampleservice.yaml
diff --git a/xos/configurations/cord-pod/cord-volt-devices.yaml b/xos/configurations/cord-pod/cord-volt-devices.yaml
new file mode 100644
index 0000000..8b41623
--- /dev/null
+++ b/xos/configurations/cord-pod/cord-volt-devices.yaml
@@ -0,0 +1,47 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Just enough Tosca to get the vSG slice running on the CORD POD
+
+imports:
+ - custom_types/xos.yaml
+
+topology_template:
+ node_templates:
+ service#volt:
+ type: tosca.nodes.VOLTService
+ properties:
+ no-create: True
+ no-delete: True
+ no-update: True
+
+ voltdev-1:
+ type: tosca.nodes.VOLTDevice
+ properties:
+ driver: pmc-olt
+ openflow_id: of:1000000000000001
+ access_devices: >
+ 2 222,
+ 3 223,
+ 4 224
+ requirements:
+ - volt_service:
+ node: service#volt
+ relationship: tosca.relationships.MemberOfService
+ - access_agent:
+ node: agent-1
+ relationship: tosca.relationships.UsesAgent
+
+ agent-1:
+ type: tosca.nodes.AccessAgent
+ properties:
+ mac: AA:BB:CC:DD:EE:FF
+ port_mappings: >
+ of:0000000000000002/2 DE:AD:BE:EF:BA:11,
+ of:0000000000000002/3 BE:EF:DE:AD:BE:EF
+ requirements:
+ - volt_service:
+ node: service#volt
+ relationship: tosca.relationships.MemberOfService
+
+
+
diff --git a/xos/configurations/cord-pod/cord-vtn-vsg.yaml b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
index bb603fe..8c73799 100644
--- a/xos/configurations/cord-pod/cord-vtn-vsg.yaml
+++ b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
@@ -16,7 +16,7 @@
replaces: service_vtr
service#volt:
- type: tosca.nodes.Service
+ type: tosca.nodes.VOLTService
requirements:
- vsg_tenant:
node: service#vsg
@@ -75,6 +75,50 @@
view_url: /admin/fabric/fabricservice/$id$/
replaces: service_fabric
+ service#ONOS_Fabric:
+ type: tosca.nodes.ONOSService
+ requirements:
+ properties:
+ kind: onos
+ view_url: /admin/onos/onosservice/$id$/
+ no_container: true
+ rest_hostname: onos-fabric
+ replaces: service_ONOS_Fabric
+
+ service#ONOS_CORD:
+ type: tosca.nodes.ONOSService
+ properties:
+ no-delete: true
+ no-create: true
+ no-update: true
+
+ vOLT_ONOS_app:
+ type: tosca.nodes.ONOSvOLTApp
+ requirements:
+ - onos_tenant:
+ node: service#ONOS_CORD
+ relationship: tosca.relationships.TenantOfService
+ - volt_service:
+ node: service#volt
+ relationship: tosca.relationships.UsedByService
+ properties:
+ 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
+ autogenerate: volt-network-cfg
+
+ vRouter_ONOS_app:
+ type: tosca.nodes.ONOSvRouterApp
+ requirements:
+ - onos_tenant:
+ node: service#ONOS_Fabric
+ relationship: tosca.relationships.TenantOfService
+ - vrouter_service:
+ node: service#vrouter
+ relationship: tosca.relationships.UsedByService
+ properties:
+ dependencies: org.onosproject.vrouter
+ autogenerate: vrouter-network-cfg
+
Private:
type: tosca.nodes.NetworkTemplate
diff --git a/xos/configurations/frontend/Makefile b/xos/configurations/frontend/Makefile
index 9e18aec..562578e 100644
--- a/xos/configurations/frontend/Makefile
+++ b/xos/configurations/frontend/Makefile
@@ -36,6 +36,8 @@
mock-cord-pod:
sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/fixtures.yaml
sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/mgmt-net.yaml
+ sudo docker-compose run xos bash -c "echo somekey > /opt/xos/synchronizers/vcpe/vcpe_public_key; python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/cord-vtn-vsg.yaml"
+ sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/cord-volt-devices.yaml
sudo docker exec frontend_xos_1 cp /opt/xos/configurations/cord-pod/xos_cord_config /opt/xos/xos_configuration/
sudo docker exec frontend_xos_1 touch /opt/xos/xos/settings.py
diff --git a/xos/core/xoslib/methods/cordsubscriber.py b/xos/core/xoslib/methods/cordsubscriber.py
index 0be9b33..b69b09d 100644
--- a/xos/core/xoslib/methods/cordsubscriber.py
+++ b/xos/core/xoslib/methods/cordsubscriber.py
@@ -28,7 +28,6 @@
class CordSubscriberIdSerializer(serializers.ModelSerializer, PlusSerializerMixin):
id = ReadOnlyField()
service_specific_id = ReadOnlyField()
- vlan_id = ReadOnlyField() # XXX remove this
c_tag = ReadOnlyField()
s_tag = ReadOnlyField()
vcpe_id = ReadOnlyField()
@@ -67,7 +66,7 @@
class Meta:
model = CordSubscriber
fields = ('humanReadableName', 'id',
- 'service_specific_id', 'vlan_id', 's_tag', 'c_tag',
+ 'service_specific_id', 's_tag', 'c_tag',
'vcpe_id', 'instance', 'instance_name', 'image', 'image_name',
'firewall_enable', 'firewall_rules',
'url_filter_enable', 'url_filter_rules', 'url_filter_level',
diff --git a/xos/core/xoslib/methods/volttenant.py b/xos/core/xoslib/methods/volttenant.py
index 229e105..25559a0 100644
--- a/xos/core/xoslib/methods/volttenant.py
+++ b/xos/core/xoslib/methods/volttenant.py
@@ -64,11 +64,6 @@
if service_specific_id is not None:
queryset = queryset.filter(service_specific_id=service_specific_id)
-# vlan_id = self.request.query_params.get('vlan_id', None)
-# if vlan_id is not None:
-# ids = [x.id for x in queryset if x.get_attribute("vlan_id", None)==vlan_id]
-# queryset = queryset.filter(id__in=ids)
-
c_tag = self.request.query_params.get('c_tag', None)
if c_tag is not None:
ids = [x.id for x in queryset if x.get_attribute("c_tag", None)==c_tag]
diff --git a/xos/core/xoslib/objects/cordsubscriber.py b/xos/core/xoslib/objects/cordsubscriber.py
index 27596b7..681b769 100644
--- a/xos/core/xoslib/objects/cordsubscriber.py
+++ b/xos/core/xoslib/objects/cordsubscriber.py
@@ -39,7 +39,6 @@
# ("cdn_enable", "vcpe.cdn_enable"),
# uplink_speed, downlink_speed, status, enable_uverse
- ("vlan_id", "volt.vlan_id"), # XXX remove this
("c_tag", "volt.c_tag"),
("s_tag", "volt.s_tag"),
diff --git a/xos/core/xoslib/static/js/xoslib/xos-backbone.js b/xos/core/xoslib/static/js/xoslib/xos-backbone.js
index 04d5fb7..d22d0ec 100644
--- a/xos/core/xoslib/static/js/xoslib/xos-backbone.js
+++ b/xos/core/xoslib/static/js/xoslib/xos-backbone.js
@@ -827,7 +827,7 @@
define_model(this, {urlRoot: CORDSUBSCRIBER_API,
modelName: "cordSubscriber",
relatedCollections: {"cordUsers": "subscriber"},
- listFields: ["id", "service_specific_id", "vlan_id", "routeable_subnet"],
+ listFields: ["id", "service_specific_id", "routeable_subnet"],
detailFields: ["id", "service_specific_id", "vcpe_id", "image_name", "instance_name",
"firewall_enable", "firewall_rules", "url_filter_enable", "url_filter_rules", "cdn_enable",
"nat_ip", "lan_ip", "wan_ip", "private_ip",
diff --git a/xos/services/cord/admin.py b/xos/services/cord/admin.py
index e7704d3..18f1e81 100644
--- a/xos/services/cord/admin.py
+++ b/xos/services/cord/admin.py
@@ -94,6 +94,59 @@
def queryset(self, request):
return VOLTTenant.get_tenant_objects_by_user(request.user)
+class AccessDeviceInline(XOSTabularInline):
+ model = AccessDevice
+ fields = ['volt_device','uplink','vlan']
+ readonly_fields = []
+ extra = 0
+# max_num = 0
+ suit_classes = 'suit-tab suit-tab-accessdevices'
+
+# @property
+# def selflink_reverse_path(self):
+# return "admin:cord_volttenant_change"
+
+class VOLTDeviceAdmin(ReadOnlyAwareAdmin):
+ list_display = ('backend_status_icon', 'name', 'openflow_id', 'driver' )
+ list_display_links = ('backend_status_icon', 'name', 'openflow_id')
+ fieldsets = [ (None, {'fields': ['backend_status_text','name','volt_service','openflow_id','driver','access_agent'],
+ 'classes':['suit-tab suit-tab-general']})]
+ readonly_fields = ('backend_status_text',)
+ inlines = [AccessDeviceInline]
+
+ suit_form_tabs = (('general','Details'), ('accessdevices','Access Devices'))
+
+class AccessDeviceAdmin(ReadOnlyAwareAdmin):
+ list_display = ('backend_status_icon', 'id', 'volt_device', 'uplink', 'vlan' )
+ list_display_links = ('backend_status_icon', 'id')
+ fieldsets = [ (None, {'fields': ['backend_status_text','volt_device','uplink','vlan'],
+ 'classes':['suit-tab suit-tab-general']})]
+ readonly_fields = ('backend_status_text',)
+
+ suit_form_tabs = (('general','Details'),)
+
+class AgentPortMappingInline(XOSTabularInline):
+ model = AgentPortMapping
+ fields = ['access_agent', 'mac', 'port']
+ readonly_fields = []
+ extra = 0
+# max_num = 0
+ suit_classes = 'suit-tab suit-tab-accessportmaps'
+
+# @property
+# def selflink_reverse_path(self):
+# return "admin:cord_volttenant_change"
+
+class AccessAgentAdmin(ReadOnlyAwareAdmin):
+ list_display = ('backend_status_icon', 'name', 'mac' )
+ list_display_links = ('backend_status_icon', 'name')
+ fieldsets = [ (None, {'fields': ['backend_status_text','name','volt_service','mac'],
+ 'classes':['suit-tab suit-tab-general']})]
+ readonly_fields = ('backend_status_text',)
+ inlines= [AgentPortMappingInline]
+
+ suit_form_tabs = (('general','Details'), ('accessportmaps', 'Port Mappings'))
+
#-----------------------------------------------------------------------------
# vCPE
#-----------------------------------------------------------------------------
@@ -398,6 +451,10 @@
admin.site.register(VOLTService, VOLTServiceAdmin)
admin.site.register(VOLTTenant, VOLTTenantAdmin)
+admin.site.register(VOLTDevice, VOLTDeviceAdmin)
+admin.site.register(AccessDevice, AccessDeviceAdmin)
+admin.site.register(AccessAgent, AccessAgentAdmin)
+
admin.site.register(VSGService, VSGServiceAdmin)
admin.site.register(VSGTenant, VSGTenantAdmin)
admin.site.register(VBNGService, VBNGServiceAdmin)
diff --git a/xos/services/cord/models.py b/xos/services/cord/models.py
index 48c9597..19b3ba6 100644
--- a/xos/services/cord/models.py
+++ b/xos/services/cord/models.py
@@ -1,5 +1,5 @@
from django.db import models
-from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, Port, AddressPool
+from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, Port, AddressPool, User
from core.models.plcorebase import StrippedCharField
import os
from django.db import models, transaction
@@ -188,15 +188,20 @@
class Meta:
app_label = "cord"
verbose_name = "vOLT Service"
- proxy = True
class VOLTTenant(Tenant):
- class Meta:
- proxy = True
-
KIND = VOLT_KIND
- default_attributes = {"vlan_id": None, "s_tag": None, "c_tag": None}
+ class Meta:
+ app_label = "cord"
+ verbose_name = "vOLT Tenant"
+
+ s_tag = models.IntegerField(null=True, blank=True, help_text="s-tag")
+ c_tag = models.IntegerField(null=True, blank=True, help_text="c-tag")
+
+ # at some point, this should probably end up part of Tenant.
+ creator = models.ForeignKey(User, related_name='created_volts', blank=True, null=True)
+
def __init__(self, *args, **kwargs):
volt_services = VOLTService.get_service_objects().all()
if volt_services:
@@ -205,32 +210,6 @@
self.cached_vcpe = None
@property
- def s_tag(self):
- return self.get_attribute("s_tag", self.default_attributes["s_tag"])
-
- @s_tag.setter
- def s_tag(self, value):
- self.set_attribute("s_tag", value)
-
- @property
- def c_tag(self):
- return self.get_attribute("c_tag", self.default_attributes["c_tag"])
-
- @c_tag.setter
- def c_tag(self, value):
- self.set_attribute("c_tag", value)
-
- # for now, vlan_id is a synonym for c_tag
-
- @property
- def vlan_id(self):
- return self.c_tag
-
- @vlan_id.setter
- def vlan_id(self, value):
- self.c_tag = value
-
- @property
def vcpe(self):
vcpe = self.get_newest_subscribed_tenant(VSGTenant)
if not vcpe:
@@ -257,28 +236,6 @@
return None
return subs[0]
- @property
- def creator(self):
- if getattr(self, "cached_creator", None):
- return self.cached_creator
- creator_id=self.get_attribute("creator_id")
- if not creator_id:
- return None
- users=User.objects.filter(id=creator_id)
- if not users:
- return None
- user=users[0]
- self.cached_creator = users[0]
- return user
-
- @creator.setter
- def creator(self, value):
- if value:
- value = value.id
- if (value != self.get_attribute("creator_id", None)):
- self.cached_creator=None
- self.set_attribute("creator_id", value)
-
def manage_vcpe(self):
# Each VOLT object owns exactly one VCPE object
@@ -347,9 +304,6 @@
super(VOLTTenant, self).save(*args, **kwargs)
model_policy_volt(self.pk)
- #self.manage_vcpe()
- #self.manage_subscriber()
- #self.cleanup_orphans()
def delete(self, *args, **kwargs):
self.cleanup_vcpe()
@@ -366,6 +320,49 @@
volt.manage_subscriber()
volt.cleanup_orphans()
+class VOLTDevice(PlCoreBase):
+ class Meta:
+ app_label = "cord"
+
+ name = models.CharField(max_length=254, help_text="name of device", null=False, blank=False)
+ volt_service = models.ForeignKey(VOLTService, related_name='volt_devices')
+ openflow_id = models.CharField(max_length=254, help_text="OpenFlow ID", null=True, blank=True)
+ driver = models.CharField(max_length=254, help_text="driver", null=True, blank=True)
+ access_agent = models.ForeignKey("AccessAgent", related_name='volt_devices', blank=True, null=True)
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+class AccessDevice(PlCoreBase):
+ class Meta:
+ app_label = "cord"
+
+ volt_device = models.ForeignKey(VOLTDevice, related_name='access_devices')
+ uplink = models.IntegerField(null=True, blank=True)
+ vlan = models.IntegerField(null=True, blank=True)
+
+ def __unicode__(self): return u'%s-%d:%d' % (self.volt_device.name,self.uplink,self.vlan)
+
+class AccessAgent(PlCoreBase):
+ class Meta:
+ app_label = "cord"
+
+ name = models.CharField(max_length=254, help_text="name of agent", null=False, blank=False)
+ volt_service = models.ForeignKey(VOLTService, related_name='access_agents')
+ mac = models.CharField(max_length=32, help_text="MAC Address or Access Agent", null=True, blank=True)
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+class AgentPortMapping(PlCoreBase):
+ class Meta:
+ app_label = "cord"
+
+ access_agent = models.ForeignKey(AccessAgent, related_name='port_mappings')
+ mac = models.CharField(max_length=32, help_text="MAC Address", null=True, blank=True)
+ port = models.CharField(max_length=32, help_text="Openflow port ID", null=True, blank=True)
+
+ def __unicode__(self): return u'%s-%s-%s' % (self.access_agent.name, self.port, self.mac)
+
+
# -------------------------------------------
# VCPE
# -------------------------------------------
diff --git a/xos/services/cord/templates/voltadmin.html b/xos/services/cord/templates/voltadmin.html
index e6887c5..807ab2c 100644
--- a/xos/services/cord/templates/voltadmin.html
+++ b/xos/services/cord/templates/voltadmin.html
@@ -1,6 +1,10 @@
<div class = "row text-center">
<div class="col-xs-12">
<a href="/admin/cord/volttenant/">vOLT Tenants</a>
+ </div><div class="col-xs-12">
+ <a href="/admin/cord/voltdevice/">vOLT Devices</a>
+ </div><div class="col-xs-12">
+ <a href="/admin/cord/accessagent/">vOLT Access Agents</a>
</div>
</div>
diff --git a/xos/synchronizers/onos/steps/sync_onosapp.py b/xos/synchronizers/onos/steps/sync_onosapp.py
index 64c9452..3a9abfc 100644
--- a/xos/synchronizers/onos/steps/sync_onosapp.py
+++ b/xos/synchronizers/onos/steps/sync_onosapp.py
@@ -18,6 +18,7 @@
from xos.logger import Logger, logging
from services.vrouter.models import VRouterService
from services.vtn.models import VTNService
+from services.cord.models import VOLTService, VOLTDevice, AccessDevice
# hpclibrary will be in steps/..
parentdir = os.path.join(os.path.dirname(__file__),"..")
@@ -243,18 +244,44 @@
return json.dumps(data, indent=4, sort_keys=True)
def get_volt_network_config(self, o, attrs):
- data = {
- "devices" : {
- "of:1000000000000001" : {
- "accessDevice" : {
- "uplink" : "2",
- "vlan" : "222",
- },
- "basic" : {
- "driver" : "pmc-olt"
- }
+ try:
+ volt = VOLTService.get_service_objects().all()[0]
+ except:
+ return None
+
+ devices = []
+ for voltdev in volt.volt_devices.all():
+ access_devices = []
+ for access in voltdev.access_devices.all():
+ access_device = {
+ "uplink" : access.uplink,
+ "vlan" : access.vlan
+ }
+ access_devices.append(access_device)
+
+ if voltdev.access_agent:
+ agent = voltdev.access_agent
+ olts = {}
+ for port_mapping in agent.port_mappings.all():
+ olts[port_mapping.port] = port_mapping.mac
+ agent_config = {
+ "olts" : olts,
+ "mac" : agent.mac
+ }
+
+ device = {
+ voltdev.openflow_id : {
+ "accessDevice" : access_devices,
+ "accessAgent" : agent_config
+ },
+ "basic" : {
+ "driver" : voltdev.driver
}
}
+ devices.append(device)
+
+ data = {
+ "devices" : devices
}
return json.dumps(data, indent=4, sort_keys=True)
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant.py b/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
index 9e3dfac..d8bc525 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
@@ -130,11 +130,9 @@
else:
logger.info("neither bbs_slice nor bbs_server is configured in the vCPE",extra=o.tologdict())
- vlan_ids = []
s_tags = []
c_tags = []
if o.volt:
- vlan_ids.append(o.volt.vlan_id) # XXX remove this
s_tags.append(o.volt.s_tag)
c_tags.append(o.volt.c_tag)
@@ -146,15 +144,14 @@
safe_macs=[]
if vcpe_service.url_filter_kind == "safebrowsing":
if o.volt and o.volt.subscriber:
- for user in o.volt.subscriber.users:
+ for user in o.volt.subscriber.devices:
level = user.get("level",None)
mac = user.get("mac",None)
if level in ["G", "PG"]:
if mac:
safe_macs.append(mac)
- fields = {"vlan_ids": vlan_ids, # XXX remove this
- "s_tags": s_tags,
+ fields = {"s_tags": s_tags,
"c_tags": c_tags,
"dnsdemux_ip": dnsdemux_ip,
"cdn_prefixes": cdn_prefixes,
@@ -199,7 +196,7 @@
if o.volt and o.volt.subscriber:
url_filter_enable = o.volt.subscriber.url_filter_enable
url_filter_level = o.volt.subscriber.url_filter_level
- url_filter_users = o.volt.subscriber.users
+ url_filter_users = o.volt.subscriber.devices
if service.url_filter_kind == "broadbandshield":
# disable url_filter if there are no bbs_addrs
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml b/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml
index 3823328..9be0f98 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml
@@ -9,10 +9,6 @@
dnsdemux_ip: {{ dnsdemux_ip }}
firewall_enable: {{ firewall_enable }}
url_filter_enable: {{ url_filter_enable }}
- vlan_ids:
- {% for vlan_id in vlan_ids %}
- - {{ vlan_id }}
- {% endfor %}
c_tags:
{% for c_tag in c_tags %}
- {{ c_tag }}
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml b/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml
index 324e274..435b721 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml
@@ -10,10 +10,6 @@
dnsdemux_ip: {{ dnsdemux_ip }}
firewall_enable: {{ firewall_enable }}
url_filter_enable: {{ url_filter_enable }}
- vlan_ids:
- {% for vlan_id in vlan_ids %}
- - {{ vlan_id }}
- {% endfor %}
c_tags:
{% for c_tag in c_tags %}
- {{ c_tag }}
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml b/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml
index 09e4d23..b24d15a 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml
@@ -10,10 +10,6 @@
dnsdemux_ip: {{ dnsdemux_ip }}
firewall_enable: {{ firewall_enable }}
url_filter_enable: {{ url_filter_enable }}
- vlan_ids:
- {% for vlan_id in vlan_ids %}
- - {{ vlan_id }}
- {% endfor %}
c_tags:
{% for c_tag in c_tags %}
- {{ c_tag }}
diff --git a/xos/synchronizers/vcpe/templates/vlan_sample.j2 b/xos/synchronizers/vcpe/templates/vlan_sample.j2
index a26c840..b73954b 100644
--- a/xos/synchronizers/vcpe/templates/vlan_sample.j2
+++ b/xos/synchronizers/vcpe/templates/vlan_sample.j2
@@ -1,5 +1,5 @@
# below is a list of all vlan_ids associated with this vcpe
-{% for vlan_id in vlan_ids %}
+{% for vlan_id in c_tags %}
{{ vlan_id }}
{% endfor %}
diff --git a/xos/tosca/custom_types/xos.m4 b/xos/tosca/custom_types/xos.m4
index 473e313..109fc1d 100644
--- a/xos/tosca/custom_types/xos.m4
+++ b/xos/tosca/custom_types/xos.m4
@@ -309,6 +309,16 @@
required: true
description: MAC address for this device.
+ tosca.nodes.VOLTService:
+ derived_from: tosca.nodes.Root
+ description: >
+ CORD: The vOLT Service
+ capabilities:
+ xos_base_service_caps
+ properties:
+ xos_base_props
+ xos_base_service_props
+
tosca.nodes.VOLTTenant:
derived_from: tosca.nodes.Root
description: >
@@ -325,6 +335,58 @@
required: false
description: c_tag, identifies which subscriber within s_tag
+ tosca.nodes.VOLTDevice:
+ derived_from: tosca.nodes.Root
+ description: >
+ CORD: A vOLT Device.
+ properties:
+ xos_base_props
+ openflow_id:
+ type: string
+ required: false
+ description: openflow id
+ driver:
+ type: string
+ required: false
+ description: driver name
+ access_devices:
+ type: string
+ required: false
+ description: list of access devices, in format "uplink vlan", multiple entries separated by commas
+
+# XXX - uncomment if we want access device to be specified as separate Tosca
+# objects, rather than encoding them into VOLTDevice.access_devices
+# tosca.nodes.AccessDevice:
+# derived_from: tosca.nodes.Root
+# description: >
+# CORD: A vOLT Access Device.
+# properties:
+# xos_base_props
+# uplink:
+# type: integer
+# required: false
+# description: uplink
+# vlan:
+# type: integer
+# required: false
+# description: vlan
+
+ tosca.nodes.AccessAgent:
+ derived_from: tosca.nodes.Root
+ description: >
+ CORD: A vOLT Access Agent.
+ properties:
+ xos_base_props
+ mac:
+ type: string
+ required: false
+ description: mac address
+ port_mappings:
+ type: string
+ required: false
+ description: list of port mappings, in format "port mac", multiple entries separated by commas
+
+
tosca.nodes.User:
derived_from: tosca.nodes.Root
@@ -966,6 +1028,12 @@
tosca.relationships.TagsObject:
derived_from: tosca.relationships.Root
+ tosca.relationships.MemberOfDevice:
+ derived_from: tosca.relationships.Root
+
+ tosca.relationships.UsesAgent:
+ derived_from: tosca.relationships.Root
+
tosca.capabilities.xos.Service:
derived_from: tosca.capabilities.Root
description: An XOS Service
diff --git a/xos/tosca/custom_types/xos.yaml b/xos/tosca/custom_types/xos.yaml
index 67d5367..8b4c669 100644
--- a/xos/tosca/custom_types/xos.yaml
+++ b/xos/tosca/custom_types/xos.yaml
@@ -766,6 +766,64 @@
required: true
description: MAC address for this device.
+ tosca.nodes.VOLTService:
+ derived_from: tosca.nodes.Root
+ description: >
+ CORD: The vOLT Service
+ capabilities:
+ scalable:
+ type: tosca.capabilities.Scalable
+ service:
+ type: tosca.capabilities.xos.Service
+ properties:
+ no-delete:
+ type: boolean
+ default: false
+ description: Do not allow Tosca to delete this object
+ no-create:
+ type: boolean
+ default: false
+ description: Do not allow Tosca to create this object
+ no-update:
+ type: boolean
+ default: false
+ description: Do not allow Tosca to update this object
+ replaces:
+ type: string
+ required: false
+ descrption: Replaces/renames this object
+ kind:
+ type: string
+ default: generic
+ description: Type of service.
+ view_url:
+ type: string
+ required: false
+ description: URL to follow when icon is clicked in the Service Directory.
+ icon_url:
+ type: string
+ required: false
+ description: ICON to display in the Service Directory.
+ enabled:
+ type: boolean
+ default: true
+ published:
+ type: boolean
+ default: true
+ description: If True then display this Service in the Service Directory.
+ public_key:
+ type: string
+ required: false
+ description: Public key to install into Instances to allows Services to SSH into them.
+ private_key_fn:
+ type: string
+ required: false
+ description: Location of private key file
+ versionNumber:
+ type: string
+ required: false
+ description: Version number of Service.
+
tosca.nodes.VOLTTenant:
derived_from: tosca.nodes.Root
description: >
@@ -789,6 +847,86 @@
required: false
description: c_tag, identifies which subscriber within s_tag
+ tosca.nodes.VOLTDevice:
+ derived_from: tosca.nodes.Root
+ description: >
+ CORD: A vOLT Device.
+ properties:
+ no-delete:
+ type: boolean
+ default: false
+ description: Do not allow Tosca to delete this object
+ no-create:
+ type: boolean
+ default: false
+ description: Do not allow Tosca to create this object
+ no-update:
+ type: boolean
+ default: false
+ description: Do not allow Tosca to update this object
+ replaces:
+ type: string
+ required: false
+ descrption: Replaces/renames this object
+ openflow_id:
+ type: string
+ required: false
+ description: openflow id
+ driver:
+ type: string
+ required: false
+ description: driver name
+ access_devices:
+ type: string
+ required: false
+ description: list of access devices, in format "uplink vlan", multiple entries separated by commas
+
+# tosca.nodes.AccessDevice:
+# derived_from: tosca.nodes.Root
+# description: >
+# CORD: A vOLT Access Device.
+# properties:
+# xos_base_props
+# uplink:
+# type: integer
+# required: false
+# description: uplink
+# vlan:
+# type: integer
+# required: false
+# description: vlan
+
+ tosca.nodes.AccessAgent:
+ derived_from: tosca.nodes.Root
+ description: >
+ CORD: A vOLT Access Agent.
+ properties:
+ no-delete:
+ type: boolean
+ default: false
+ description: Do not allow Tosca to delete this object
+ no-create:
+ type: boolean
+ default: false
+ description: Do not allow Tosca to create this object
+ no-update:
+ type: boolean
+ default: false
+ description: Do not allow Tosca to update this object
+ replaces:
+ type: string
+ required: false
+ descrption: Replaces/renames this object
+ mac:
+ type: string
+ required: false
+ description: mac address
+ port_mappings:
+ type: string
+ required: false
+ description: list of port mappings, in format "port mac", multiple entries separated by commas
+
+
tosca.nodes.User:
derived_from: tosca.nodes.Root
@@ -1715,6 +1853,9 @@
tosca.relationships.TagsObject:
derived_from: tosca.relationships.Root
+ tosca.relationships.MemberOfDevice:
+ derived_from: tosca.relationships.Root
+
tosca.capabilities.xos.Service:
derived_from: tosca.capabilities.Root
description: An XOS Service
diff --git a/xos/tosca/resources/accessagent.py b/xos/tosca/resources/accessagent.py
new file mode 100644
index 0000000..368ce55
--- /dev/null
+++ b/xos/tosca/resources/accessagent.py
@@ -0,0 +1,56 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.cord.models import AccessAgent, VOLTDevice, VOLTService, AgentPortMapping
+from xosresource import XOSResource
+
+class XOSAccessAgent(XOSResource):
+ provides = "tosca.nodes.AccessAgent"
+ xos_model = AccessAgent
+ copyin_props = ["mac"]
+
+ def get_xos_args(self, throw_exception=True):
+ args = super(XOSAccessAgent, self).get_xos_args()
+
+ volt_service_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+ if volt_service_name:
+ args["volt_service"] = self.get_xos_object(VOLTService, throw_exception=throw_exception, name=volt_service_name)
+
+ return args
+
+ def postprocess(self, obj):
+ # For convenient, allow the port mappings to be specified by a Tosca
+ # string with commas between lines.
+ # <port> <mac>,
+ # <port> <mac>,
+ # ...
+ # <port> <mac>
+
+ port_mappings_str = self.get_property("port_mappings")
+ port_mappings = []
+ if port_mappings_str:
+ lines = [x.strip() for x in port_mappings_str.split(",")]
+ for line in lines:
+ if not (" " in line):
+ raise "Malformed port mapping `%s`", line
+ (port, mac) = line.split(" ")
+ port=port.strip()
+ mac=mac.strip()
+ port_mappings.append( (port, mac) )
+
+ for apm in list(AgentPortMapping.objects.filter(access_agent=obj)):
+ if (apm.port, apm.mac) not in port_mappings:
+ print "Deleting AgentPortMapping '%s'" % apm
+ apm.delete()
+
+ for port_mapping in port_mappings:
+ existing_objs = AgentPortMapping.objects.filter(access_agent=obj, port=port_mapping[0], mac=port_mapping[1])
+ if not existing_objs:
+ apm = AgentPortMapping(access_agent=obj, port=port_mapping[0], mac=port_mapping[1])
+ apm.save()
+ print "Created AgentPortMapping '%s'" % apm
+
diff --git a/xos/tosca/resources/accessdevice.py b/xos/tosca/resources/accessdevice.py
new file mode 100644
index 0000000..94deb86
--- /dev/null
+++ b/xos/tosca/resources/accessdevice.py
@@ -0,0 +1,40 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.cord.models import AccessDevice, VOLTDevice
+from xosresource import XOSResource
+
+class XOSAccessDevice(XOSResource):
+ provides = "tosca.nodes.AccessDevice"
+ xos_model = AccessDevice
+ copyin_props = ["uplink", "vlan"]
+ name_field = None
+
+ def get_xos_args(self, throw_exception=True):
+ args = super(XOSAccessDevice, self).get_xos_args()
+
+ volt_device_name = self.get_requirement("tosca.relationships.MemberOfDevice", throw_exception=throw_exception)
+ if volt_device_name:
+ args["volt_device"] = self.get_xos_object(VOLTDevice, throw_exception=throw_exception, name=volt_device_name)
+
+ return args
+
+ # AccessDevice has no name field, so we rely on matching the keys. We assume
+ # the for a given VOLTDevice, there is only one AccessDevice per (uplink, vlan)
+ # pair.
+
+ def get_existing_objs(self):
+ args = self.get_xos_args(throw_exception=False)
+ volt_device = args.get("volt_device", None)
+ uplink = args.get("uplink", None)
+ vlan = args.get("vlan", None)
+ if (volt_device is not None) and (uplink is not None) and (vlan is not None):
+ existing_obj = self.get_xos_object(AccessDevice, volt_device=volt_device, uplink=uplink, vlan=vlan, throw_exception=False)
+ if existing_obj:
+ return [ existing_obj ]
+ return []
+
diff --git a/xos/tosca/resources/voltdevice.py b/xos/tosca/resources/voltdevice.py
new file mode 100644
index 0000000..f1c6830
--- /dev/null
+++ b/xos/tosca/resources/voltdevice.py
@@ -0,0 +1,52 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.cord.models import VOLTDevice, VOLTService, AccessDevice, AccessAgent
+from xosresource import XOSResource
+
+class XOSVOLTDevice(XOSResource):
+ provides = "tosca.nodes.VOLTDevice"
+ xos_model = VOLTDevice
+ copyin_props = ["openflow_id", "driver"]
+
+ def get_xos_args(self, throw_exception=True):
+ args = super(XOSVOLTDevice, self).get_xos_args()
+
+ volt_service_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+ if volt_service_name:
+ args["volt_service"] = self.get_xos_object(VOLTService, throw_exception=throw_exception, name=volt_service_name)
+
+ agent_name = self.get_requirement("tosca.relationships.UsesAgent", throw_exception=throw_exception)
+ if agent_name:
+ args["access_agent"] = self.get_xos_object(AccessAgent, throw_exception=throw_exception, name=agent_name)
+
+ return args
+
+ def postprocess(self, obj):
+ access_devices_str = self.get_property("access_devices")
+ access_devices = []
+ if access_devices_str:
+ lines = [x.strip() for x in access_devices_str.split(",")]
+ for line in lines:
+ if not (" " in line):
+ raise "Malformed access device `%s`", line
+ (uplink, vlan) = line.split(" ")
+ uplink=int(uplink.strip())
+ vlan=int(vlan.strip())
+ access_devices.append( (uplink, vlan) )
+
+ for ad in list(AccessDevice.objects.filter(volt_device=obj)):
+ if (ad.uplink, ad.vlan) not in access_devices:
+ print "Deleting AccessDevice '%s'" % ad
+ ad.delete()
+
+ for access_device in access_devices:
+ existing_objs = AccessDevice.objects.filter(volt_device=obj, uplink=access_device[0], vlan=access_device[1])
+ if not existing_objs:
+ ad = AccessDevice(volt_device=obj, uplink=access_device[0], vlan=access_device[1])
+ ad.save()
+ print "Created AccessDevice '%s'" % ad
diff --git a/xos/tosca/resources/voltservice.py b/xos/tosca/resources/voltservice.py
new file mode 100644
index 0000000..57cf846
--- /dev/null
+++ b/xos/tosca/resources/voltservice.py
@@ -0,0 +1,15 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.cord.models import VOLTService
+
+from service import XOSService
+
+class XOSVOLTService(XOSService):
+ provides = "tosca.nodes.VOLTService"
+ xos_model = VOLTService
+ copyin_props = ["view_url", "icon_url", "kind", "enabled", "published", "public_key", "private_key_fn", "versionNumber"]
diff --git a/xos/xos/settings.py b/xos/xos/settings.py
index 2f8fa27..7835689 100644
--- a/xos/xos/settings.py
+++ b/xos/xos/settings.py
@@ -243,6 +243,8 @@
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
+ },'django.db.backends': {
+ 'level': 'WARNING',
},
}
}