Start of Fabric service synchronizer
diff --git a/xos/configurations/cord-pod/Makefile b/xos/configurations/cord-pod/Makefile
index f0b3c3c..1b9e967 100644
--- a/xos/configurations/cord-pod/Makefile
+++ b/xos/configurations/cord-pod/Makefile
@@ -33,6 +33,9 @@
vtn: vtn-external.yaml
sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/vtn-external.yaml
+fabric: fabric.yaml
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/fabric.yaml
+
cord: vsg_custom_images
sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/mgmt-net.yaml
sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/cord-vtn-vsg.yaml
@@ -53,6 +56,9 @@
vtn-external.yaml:
export SETUPDIR=.; bash ./make-vtn-external-yaml.sh
+fabric.yaml:
+ export SETUPDIR=.; bash ./make-fabric-yaml.sh
+
virtualbng_json:
export SETUPDIR=.; bash ./make-virtualbng-json.sh
diff --git a/xos/configurations/cord-pod/cord-vtn-vsg.yaml b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
index 8c73799..44d4fbb 100644
--- a/xos/configurations/cord-pod/cord-vtn-vsg.yaml
+++ b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
@@ -69,21 +69,6 @@
node: addresses_exampleservice-public
relationship: tosca.relationships.ProvidesAddresses
- service#fabric:
- type: tosca.nodes.FabricService
- properties:
- 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
@@ -92,6 +77,13 @@
no-create: true
no-update: true
+ service#ONOS_Fabric:
+ type: tosca.nodes.ONOSService
+ properties:
+ no-delete: true
+ no-create: true
+ no-update: true
+
vOLT_ONOS_app:
type: tosca.nodes.ONOSvOLTApp
requirements:
diff --git a/xos/configurations/cord-pod/docker-compose-bootstrap.yml b/xos/configurations/cord-pod/docker-compose-bootstrap.yml
index d481767..9f17c42 100644
--- a/xos/configurations/cord-pod/docker-compose-bootstrap.yml
+++ b/xos/configurations/cord-pod/docker-compose-bootstrap.yml
@@ -119,6 +119,21 @@
max-size: "100k"
max-file: "5"
+xos_synchronizer_fabric:
+ image: xosproject/xos-synchronizer-openstack
+ command: bash -c "sleep 120; python /opt/xos/synchronizers/fabric/fabric-synchronizer.py -C /opt/xos/synchronizers/fabric/fabric_synchronizer_config"
+ labels:
+ org.xosproject.kind: synchronizer
+ org.xosproject.target: fabric
+ links:
+ - xos_db
+ volumes:
+ - .:/root/setup:ro
+ log_driver: "json-file"
+ log_opt:
+ max-size: "100k"
+ max-file: "5"
+
xos_bootstrap_ui:
command: python /opt/xos/manage.py runserver 0.0.0.0:81 --insecure --makemigrations
image: xosproject/xos
@@ -138,4 +153,3 @@
log_opt:
max-size: "100k"
max-file: "5"
-
diff --git a/xos/configurations/cord-pod/make-fabric-yaml.sh b/xos/configurations/cord-pod/make-fabric-yaml.sh
new file mode 100644
index 0000000..a829690
--- /dev/null
+++ b/xos/configurations/cord-pod/make-fabric-yaml.sh
@@ -0,0 +1,71 @@
+FN=$SETUPDIR/fabric.yaml
+
+rm -f $FN
+
+cat >> $FN <<EOF
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+imports:
+ - custom_types/xos.yaml
+
+description: generate fabric configuration
+
+topology_template:
+ node_templates:
+
+ 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#fabric:
+ type: tosca.nodes.FabricService
+ properties:
+ view_url: /admin/fabric/fabricservice/\$id\$/
+ replaces: service_fabric
+
+
+EOF
+
+NODES=$( bash -c "source $SETUPDIR/admin-openrc.sh ; nova host-list" |grep compute|awk '{print $2}' )
+I=0
+for NODE in $NODES; do
+ echo $NODE
+ cat >> $FN <<EOF
+ $NODE:
+ type: tosca.nodes.Node
+
+ # Fabric location field for node $NODE
+ ${NODE}_location_tag:
+ type: tosca.nodes.Tag
+ properties:
+ name: location
+ value: of:0000000000000001/1
+ requirements:
+ - target:
+ node: $NODE
+ relationship: tosca.relationships.TagsObject
+ - service:
+ node: service#ONOS_Fabric
+ relationship: tosca.relationships.MemberOfService
+EOF
+done
+
+cat >> $FN <<EOF
+ Fabric_ONOS_app:
+ type: tosca.nodes.ONOSApp
+ requirements:
+ - onos_tenant:
+ node: service#ONOS_Fabric
+ relationship: tosca.relationships.TenantOfService
+ - fabric_service:
+ node: service#fabric
+ relationship: tosca.relationships.UsedByService
+ properties:
+ dependencies: org.onosproject.lldpprovider, org.onosproject.hostprovider, org.onosproject.openflow-base, org.onosproject.openflow, org.onosproject.drivers, org.onosproject.segmentrouting
+EOF
diff --git a/xos/services/fabric/admin.py b/xos/services/fabric/admin.py
index 5dc5923..e372a7d 100644
--- a/xos/services/fabric/admin.py
+++ b/xos/services/fabric/admin.py
@@ -35,7 +35,7 @@
verbose_name_plural = "Fabric Services"
list_display = ("backend_status_icon", "name", "enabled")
list_display_links = ('backend_status_icon', 'name', )
- fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description', "view_url", "icon_url", ],
+ fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description', "view_url", "icon_url", "autoconfig", ],
'classes':['suit-tab suit-tab-general']})]
readonly_fields = ('backend_status_text', )
inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
@@ -60,4 +60,3 @@
return FabricService.get_service_objects_by_user(request.user)
admin.site.register(FabricService, FabricServiceAdmin)
-
diff --git a/xos/services/fabric/models.py b/xos/services/fabric/models.py
index 0bf6a14..bd37416 100644
--- a/xos/services/fabric/models.py
+++ b/xos/services/fabric/models.py
@@ -1,30 +1,16 @@
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.plcorebase import StrippedCharField
-import os
-from django.db import models, transaction
-from django.forms.models import model_to_dict
-from django.db.models import Q
-from operator import itemgetter, attrgetter, methodcaller
-from core.models import Tag
-from core.models.service import LeastLoadedNodeScheduler
+from core.models import Service
import traceback
from xos.exceptions import *
from xos.config import Config
-class ConfigurationError(Exception):
- pass
-
FABRIC_KIND = "fabric"
-CORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
-
class FabricService(Service):
KIND = FABRIC_KIND
class Meta:
app_label = "fabric"
verbose_name = "Fabric Service"
- proxy = True
-
+ autoconfig = models.BooleanField(default=True, help_text="Autoconfigure the fabric")
diff --git a/xos/synchronizers/fabric/fabric-synchronizer.py b/xos/synchronizers/fabric/fabric-synchronizer.py
new file mode 100755
index 0000000..84bec4f
--- /dev/null
+++ b/xos/synchronizers/fabric/fabric-synchronizer.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# This imports and runs ../../xos-observer.py
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/synchronizers/fabric/fabric_synchronizer_config b/xos/synchronizers/fabric/fabric_synchronizer_config
new file mode 100644
index 0000000..2ed56fe
--- /dev/null
+++ b/xos/synchronizers/fabric/fabric_synchronizer_config
@@ -0,0 +1,23 @@
+# Required by XOS
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+# Required by XOS
+[api]
+nova_enabled=True
+
+# Sets options for the synchronizer
+[observer]
+name=fabric
+dependency_graph=/opt/xos/synchronizers/fabric/model-deps
+steps_dir=/opt/xos/synchronizers/fabric/steps
+sys_dir=/opt/xos/synchronizers/fabric/sys
+logfile=console
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+proxy_ssh=False
diff --git a/xos/synchronizers/fabric/model-deps b/xos/synchronizers/fabric/model-deps
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/xos/synchronizers/fabric/model-deps
@@ -0,0 +1 @@
+{}
diff --git a/xos/synchronizers/fabric/run.sh b/xos/synchronizers/fabric/run.sh
new file mode 100755
index 0000000..4e0c214
--- /dev/null
+++ b/xos/synchronizers/fabric/run.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+python fabric-synchronizer.py -C $XOS_DIR/synchronizers/fabric/fabric_synchronizer_config
diff --git a/xos/synchronizers/fabric/start.sh b/xos/synchronizers/fabric/start.sh
new file mode 100755
index 0000000..8d02bf3
--- /dev/null
+++ b/xos/synchronizers/fabric/start.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+nohup python fabric-synchronizer.py -C $XOS_DIR/synchronizers/fabric/fabric_synchronizer_config > /dev/null 2>&1 &
diff --git a/xos/synchronizers/fabric/steps/sync_host.yaml b/xos/synchronizers/fabric/steps/sync_host.yaml
new file mode 100644
index 0000000..58bccba
--- /dev/null
+++ b/xos/synchronizers/fabric/steps/sync_host.yaml
@@ -0,0 +1,20 @@
+---
+- hosts: 127.0.0.1
+ connection: local
+ vars:
+ rest_hostname: {{ rest_hostname }}
+ rest_port: {{ rest_port }}
+ rest_endpoint: {{ rest_endpoint }}
+ rest_json: '{{ rest_json }}'
+
+ tasks:
+ - debug: var=rest_json
+
+ - name: Call Fabric REST API
+ uri:
+ url: http://{{ '{{' }} rest_hostname {{ '}}' }}:{{ '{{' }} rest_port {{ '}}' }}/{{ '{{' }} rest_endpoint {{ '}}' }} #http://localhost:8181/onos/v1/network/configuration/
+ body: "{{ '{{' }} rest_json {{ '}}' }}"
+ body_format: raw
+ method: POST
+ user: karaf
+ password: karaf
diff --git a/xos/synchronizers/fabric/steps/sync_vroutertenant.py b/xos/synchronizers/fabric/steps/sync_vroutertenant.py
new file mode 100644
index 0000000..fd77ca2
--- /dev/null
+++ b/xos/synchronizers/fabric/steps/sync_vroutertenant.py
@@ -0,0 +1,103 @@
+import os
+import base64
+from collections import defaultdict
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models import Controller
+from core.models import Image, ControllerImages
+from xos.logger import observer_logger as logger
+from synchronizers.base.ansible import *
+from services.vrouter.models import VRouterTenant
+from services.onos.models import ONOSService
+from services.fabric.models import FabricService
+import json
+
+class SyncVRouterTenant(SyncStep):
+ provides=[VRouterTenant]
+ observes = VRouterTenant
+ requested_interval=30
+ playbook='sync_host.yaml'
+
+ def get_fabric_onos_service(self):
+ fos = None
+ fs = FabricService.get_service_objects().all()[0]
+ if fs.subscribed_tenants.exists():
+ app = fs.subscribed_tenants.all()[0]
+ if app.provider_service:
+ ps = app.provider_service
+ fos = ONOSService.get_service_objects().filter(id=ps.id)[0]
+ return fos
+
+ def get_node_tag(self, node, tagname):
+ tags = Tag.select_by_content_object(node).filter(name=tagname)
+ return tags[0].value
+
+ def fetch_pending(self, deleted):
+ fs = FabricService.get_service_objects().all()[0]
+ if not fs.autoconfig:
+ return None
+
+ if (not deleted):
+ objs = VRouterTenant.get_tenant_objects().filter(Q(lazy_blocked=False))
+ else:
+ objs = VRouterTenant.get_deleted_tenant_objects()
+
+ return objs
+
+ def map_sync_inputs(self, vroutertenant):
+
+ fos = self.get_fabric_onos_service()
+
+ name = None
+ instance = None
+ # VRouterTenant setup is kind of hacky right now, we'll
+ # need to revisit. The idea is:
+ # * Look up the instance corresponding to the address
+ # * Look up the node running the instance
+ # * Get the "location" tag, push to the fabric
+ #
+ # Do we have a vCPE subscriber_tenant?
+ if (vroutertenant.subscriber_tenant):
+ sub = vroutertenant.subscriber_tenant
+ if (sub.kind == 'vCPE'):
+ instance_id = sub.get_attribute("instance_id")
+ if instance_id:
+ instance = Instance.objects.filter(id=instance_id)[0]
+ name = str(sub)
+ else:
+ # Maybe the VRouterTenant is for an instance
+ instance_id = vroutertenant.get_attribute("tenant_for_instance_id")
+ if instance_id:
+ instance = Instance.objects.filter(id=instance_id)[0]
+ name = str(instance)
+
+ node = instance.node
+ location = self.get_node_tag(node, "location")
+
+ # Is it a POST or DELETE?
+
+ # Create JSON
+ data = {
+ "%s/-1"%vroutertenant.public_mac : {
+ "basic" : {
+ "ips" : [ vroutertenant.public_ip ],
+ "location" : location
+ }
+ }
+ }
+
+ rest_json = json.dumps(data, indent=4)
+
+ fields = {
+ 'rest_hostname': fos.rest_hostname,
+ 'rest_port': fos.rest_port,
+ 'rest_json': rest_json,
+ 'rest_endpoint': "onos/v1/network/configuration/hosts",
+ 'ansible_tag': '%s'%name, # name of ansible playbook
+ }
+ return fields
+
+ def map_sync_outputs(self, controller_image, res):
+ pass
diff --git a/xos/synchronizers/fabric/stop.sh b/xos/synchronizers/fabric/stop.sh
new file mode 100755
index 0000000..d35b057
--- /dev/null
+++ b/xos/synchronizers/fabric/stop.sh
@@ -0,0 +1 @@
+pkill -9 -f fabric-synchronizer.py