Merge branch 'master' into feature/lts
diff --git a/containers/onboarding_synchronizer/Dockerfile b/containers/onboarding_synchronizer/Dockerfile
index 967e234..b86cbb1 100644
--- a/containers/onboarding_synchronizer/Dockerfile
+++ b/containers/onboarding_synchronizer/Dockerfile
@@ -10,12 +10,20 @@
# This container must be started in privileged mode.
RUN apt-get install -y curl
-# iptables
-ENV DOCKER_BUCKET=get.docker.com
-ENV DOCKER_VERSION=1.8.3
-ENV DOCKER_SHA256=f024bc65c45a3778cf07213d26016075e8172de8f6e4b5702bedde06c241650f
-RUN curl -fSL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-$DOCKER_VERSION" -o /usr/local/bin/docker && echo "${DOCKER_SHA256} /usr/local/bin/docker" | sha256sum -c - && chmod +x /usr/local/bin/docker
+# XXX version 1.10.3
+ENV DOCKER_BUCKET get.docker.com
+ENV DOCKER_VERSION 1.10.3
+ENV DOCKER_SHA256 d0df512afa109006a450f41873634951e19ddabf8c7bd419caeb5a526032d86d
+RUN curl -fSL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-$DOCKER_VERSION" -o /usr/local/bin/docker && echo "${DOCKER_SHA256} /usr/local/bin/docker" | sha256sum -c - && chmod +x /usr/local/bin/docker
+
+# XXX vserioin 1.8.3
+#ENV DOCKER_BUCKET=get.docker.com
+#ENV DOCKER_VERSION=1.8.3
+#ENV DOCKER_SHA256=f024bc65c45a3778cf07213d26016075e8172de8f6e4b5702bedde06c241650f
+#RUN curl -fSL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-$DOCKER_VERSION" -o /usr/local/bin/docker && echo "${DOCKER_SHA256} /usr/local/bin/docker" | sha256sum -c - && chmod +x /usr/local/bin/docker
+
+# XXX version 1.8.3
# XXX uncomment the following 6 lines to run docker-in-docker
# comment them out if using the docker socket in a volume instead
#ENV DIND_COMMIT=3b5fac462d21ca164b3778647420016315289034
diff --git a/views/ngXosLib/karma.conf.js b/views/ngXosLib/karma.conf.js
index 9d880a0..d9bbaa2 100644
--- a/views/ngXosLib/karma.conf.js
+++ b/views/ngXosLib/karma.conf.js
@@ -94,7 +94,7 @@
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: [
'PhantomJS',
- // 'Chrome'
+ //'Chrome'
],
diff --git a/views/ngXosLib/xosHelpers/spec/services/helpers/comparator.test.js b/views/ngXosLib/xosHelpers/spec/services/helpers/comparator.test.js
new file mode 100644
index 0000000..66e26d3
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/services/helpers/comparator.test.js
@@ -0,0 +1,60 @@
+(function () {
+ 'use strict';
+
+ describe('The xos.helper module', function(){
+ describe('The Comparator service', () => {
+
+ let service;
+
+ // load the application module
+ beforeEach(module('xos.helpers'));
+
+ // inject the cartService
+ beforeEach(inject(function (_Comparator_) {
+ // The injector unwraps the underscores (_) from around the parameter names when matching
+ service = _Comparator_;
+ }));
+
+ describe('given a string', () => {
+ it('should return true if expected is substring of actual', () => {
+ const res = service('test', 'te');
+ expect(res).toBeTruthy();
+ });
+
+ it('should return false if expected is not substring of actual', () => {
+ const res = service('test', 'ab');
+ expect(res).toBeFalsy();
+ });
+ });
+
+ describe('given a boolean', () => {
+ it('should return true if values match', () => {
+ expect(service(false, false)).toBeTruthy();
+ expect(service(true, true)).toBeTruthy();
+ expect(service(0, false)).toBeTruthy();
+ expect(service(1, true)).toBeTruthy();
+ });
+
+ it('should return false if values doesn\'t match', () => {
+ expect(service(false, true)).toBeFalsy();
+ expect(service(true, false)).toBeFalsy();
+ expect(service(1, false)).toBeFalsy();
+ expect(service(0, true)).toBeFalsy();
+ });
+ });
+
+ describe('given a number', () => {
+ // NOTE if numbers should we compare with === ??
+ it('should return true if expected is substring of actual', () => {
+ expect(service(12, 1)).toBeTruthy();
+ });
+
+ it('should return false if expected is not substring of actual', () => {
+ expect(service(12, 3)).toBeFalsy();
+ });
+ });
+
+ });
+ });
+
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/ui/table.test.js b/views/ngXosLib/xosHelpers/spec/ui/table.test.js
index 1535c6e..2ec8006 100644
--- a/views/ngXosLib/xosHelpers/spec/ui/table.test.js
+++ b/views/ngXosLib/xosHelpers/spec/ui/table.test.js
@@ -124,15 +124,22 @@
label: 'Label 1',
prop: 'label-1',
type: 'boolean'
+ },
+ {
+ label: 'Label 2',
+ prop: 'label-2',
+ type: 'boolean'
}
]
};
scope.data = [
{
- 'label-1': true
+ 'label-1': true,
+ 'label-2': 1
},
{
- 'label-1': false
+ 'label-1': false,
+ 'label-2': 0
}
];
compileElement();
@@ -156,6 +163,30 @@
expect(td1).toContainElement('select');
expect(td1).not.toContainElement('input');
});
+
+ it('should correctly filter results', () => {
+ isolatedScope.query = {
+ 'label-1': false
+ };
+ scope.$digest();
+ expect(isolatedScope.query['label-1']).toBeFalsy();
+ var tr = $(element).find('tbody:last-child > tr');
+ var icon = $(tr[0]).find('td i');
+ expect(tr.length).toEqual(1);
+ expect(icon).toHaveClass('glyphicon-remove');
+ });
+
+ it('should correctly filter results if the field is in the form of 0|1', () => {
+ isolatedScope.query = {
+ 'label-2': false
+ };
+ scope.$digest();
+ expect(isolatedScope.query['label-1']).toBeFalsy();
+ var tr = $(element).find('tbody:last-child > tr');
+ var icon = $(tr[0]).find('td i');
+ expect(tr.length).toEqual(1);
+ expect(icon).toHaveClass('glyphicon-remove');
+ });
});
});
diff --git a/views/ngXosLib/xosHelpers/src/services/helpers/ui/comparator.service.js b/views/ngXosLib/xosHelpers/src/services/helpers/ui/comparator.service.js
new file mode 100644
index 0000000..77e6210
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/helpers/ui/comparator.service.js
@@ -0,0 +1,96 @@
+(function() {
+ 'use strict';
+
+ /**
+ * @ngdoc service
+ * @name xos.uiComponents.Comparator
+ * @description
+ * This factory define a function that replace the native angular.filter comparator.
+ *
+ * It is done to allow the comparation between (0|1) values with booleans.
+ * >Note that this factory return a single function, not an object.
+ *
+ * The tipical usage of this factory is inside an `ng-repeat`
+ * @example
+ * <example module="comparator">
+ * <file name="index.html">
+ * <div ng-controller="sample as vm">
+ * <div class="row">
+ * <div class="col-xs-6">
+ * <label>Filter by name:</label>
+ * <input class="form-control" type="text" ng-model="vm.query.name"/>
+ * </div>
+ * <div class="col-xs-6">
+ * <label>Filter by status:</label>
+ * <select
+ * ng-model="vm.query.status"
+ * ng-options="i for i in [true, false]">
+ * </select>
+ * </div>
+ * </div>
+ * <div ng-repeat="item in vm.data | filter:vm.query:vm.comparator">
+ * <div class="row">
+ * <div class="col-xs-6">{{item.name}}</div>
+ * <div class="col-xs-6">{{item.status}}</div>
+ * </div>
+ * </div>
+ * </div>
+ * </file>
+ * <file name="script.js">
+ * angular.module('comparator', ['xos.uiComponents'])
+ * .controller('sample', function(Comparator){
+ * this.comparator = Comparator;
+ * this.data = [
+ * {name: 'Jhon', status: 1},
+ * {name: 'Jack', status: 0},
+ * {name: 'Mike', status: 1},
+ * {name: 'Scott', status: 0}
+ * ];
+ * });
+ * </file>
+ * </example>
+ **/
+
+ angular
+ .module('xos.uiComponents')
+ .factory('Comparator', comparator);
+
+ function comparator() {
+
+ return function(actual, expected){
+
+ if (angular.isUndefined(actual)) {
+ // No substring matching against `undefined`
+ return false;
+ }
+ if ((actual === null) || (expected === null)) {
+ // No substring matching against `null`; only match against `null`
+ return actual === expected;
+ }
+ if (angular.isObject(expected) || (angular.isObject(actual))){
+ return angular.equals(expected, actual);
+ }
+
+ if(_.isBoolean(actual) || _.isBoolean(expected)){
+ if(actual === 0 || actual === 1){
+ actual = !!actual;
+ }
+ return angular.equals(expected, actual);
+ }
+
+ if(!angular.isString(actual) || !angular.isString(expected)){
+ if(angular.isDefined(actual.toString) && angular.isDefined(expected.toString)){
+ actual = actual.toString();
+ expected = expected.toString();
+ }
+ else {
+ return actual === expected;
+ }
+ }
+
+ actual = actual.toLowerCase() + '';
+ expected = expected.toLowerCase() + '';
+ return actual.indexOf(expected) !== -1;
+ };
+ }
+})();
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table/table.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table/table.component.js
index 7911b7a..371f46c 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table/table.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table/table.component.js
@@ -387,7 +387,7 @@
</tr>
</tbody>
<tbody>
- <tr ng-repeat="item in vm.data | filter:vm.query | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">
+ <tr ng-repeat="item in vm.data | filter:vm.query:vm.comparator | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">
<td ng-repeat="col in vm.columns" link-wrapper>
<span ng-if="!col.type">{{item[col.prop]}}</span>
<span ng-if="col.type === 'boolean'">
@@ -448,7 +448,9 @@
`,
bindToController: true,
controllerAs: 'vm',
- controller: function(_, $scope){
+ controller: function(_, $scope, Comparator){
+
+ this.comparator = Comparator;
this.loader = true;
diff --git a/xos/api/service/vbng/debug.py b/xos/api/service/vbng/debug.py
deleted file mode 100644
index 8ecec0f..0000000
--- a/xos/api/service/vbng/debug.py
+++ /dev/null
@@ -1,61 +0,0 @@
-from rest_framework.decorators import api_view
-from rest_framework.response import Response
-from rest_framework.reverse import reverse
-from rest_framework import serializers
-from rest_framework import generics
-from rest_framework import viewsets
-from rest_framework.decorators import detail_route, list_route
-from rest_framework.views import APIView
-from core.models import *
-from django.forms import widgets
-from django.conf.urls import patterns, url
-from services.cord.models import VOLTTenant, VBNGTenant, CordSubscriberRoot
-from core.xoslib.objects.cordsubscriber import CordSubscriber
-from api.xosapi_helpers import PlusModelSerializer, XOSViewSet
-from django.shortcuts import get_object_or_404
-from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
-from xos.exceptions import *
-import json
-import subprocess
-
-if hasattr(serializers, "ReadOnlyField"):
- # rest_framework 3.x
- ReadOnlyField = serializers.ReadOnlyField
-else:
- # rest_framework 2.x
- ReadOnlyField = serializers.Field
-
-class CordDebugIdSerializer(PlusModelSerializer):
- # Swagger is failing because CordDebugViewSet has neither a model nor
- # a serializer_class. Stuck this in here as a placeholder for now.
- id = ReadOnlyField()
- class Meta:
- model = CordSubscriber
-
-class CordDebugViewSet(XOSViewSet):
- base_name = "debug"
- method_name = "debug"
- method_kind = "viewset"
- serializer_class = CordDebugIdSerializer
-
- @classmethod
- def get_urlpatterns(self, api_path="^"):
- patterns = []
- patterns.append( url(api_path + "debug/vbng_dump/$", self.as_view({"get": "get_vbng_dump"}), name="vbng_dump"))
- return patterns
-
- # contact vBNG service and dump current list of mappings
- def get_vbng_dump(self, request, pk=None):
- result=subprocess.check_output(["curl", "http://10.0.3.136:8181/onos/virtualbng/privateip/map"])
- if request.GET.get("theformat",None)=="text":
- from django.http import HttpResponse
- result = json.loads(result)["map"]
-
- lines = []
- for row in result:
- for k in row.keys():
- lines.append( "%s %s" % (k, row[k]) )
-
- return HttpResponse("\n".join(lines), content_type="text/plain")
- else:
- return Response( {"vbng_dump": json.loads(result)["map"] } )
diff --git a/xos/configurations/cord-pod/Makefile b/xos/configurations/cord-pod/Makefile
index 6aedc0a..b2d942a 100644
--- a/xos/configurations/cord-pod/Makefile
+++ b/xos/configurations/cord-pod/Makefile
@@ -20,6 +20,30 @@
echo "[ONBOARDING]"
# on-board any services here
bash ../common/wait_for_onboarding_ready.sh 81 xos
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/configurations/cord-pod/disable-onboarding.yaml
+ sudo cp id_rsa key_import/vsg_rsa
+ sudo cp id_rsa.pub key_import/vsg_rsa.pub
+ sudo cp id_rsa key_import/volt_rsa
+ sudo cp id_rsa.pub key_import/volt_rsa.pub
+ sudo cp id_rsa key_import/onos_rsa
+ sudo cp id_rsa key_import/onos_rsa.pub
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/vrouter/vrouter-onboard.yaml
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/volt/volt-onboard.yaml
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/vsg/vsg-onboard.yaml
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/vtn/vtn-onboard.yaml
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/onos/onos-onboard.yaml
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/fabric/fabric-onboard.yaml
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/vtr/vtr-onboard.yaml
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/configurations/cord-pod/synchronizers.yaml
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/configurations/cord-pod/enable-onboarding.yaml
+ bash ../common/wait_for_onboarding_ready.sh 81 services/vrouter
+ bash ../common/wait_for_onboarding_ready.sh 81 services/volt
+ bash ../common/wait_for_onboarding_ready.sh 81 services/vsg
+ bash ../common/wait_for_onboarding_ready.sh 81 services/vtn
+ bash ../common/wait_for_onboarding_ready.sh 81 services/onos
+ bash ../common/wait_for_onboarding_ready.sh 81 services/fabric
+ bash ../common/wait_for_onboarding_ready.sh 81 services/vtr
+ bash ../common/wait_for_onboarding_ready.sh 81 xos
bash ../common/wait_for_xos_port.sh 80
podconfig: nodes.yaml images.yaml
diff --git a/xos/configurations/cord-pod/cord-vtn-vsg.yaml b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
index 44d4fbb..6996527 100644
--- a/xos/configurations/cord-pod/cord-vtn-vsg.yaml
+++ b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
@@ -25,6 +25,10 @@
view_url: /admin/cord/voltservice/$id$/
kind: vOLT
replaces: service_volt
+ public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+ private_key_fn: /opt/xos/services/volt/keys/volt_rsa
+ artifacts:
+ pubkey: /opt/xos/services/volt/keys/volt_rsa.pub
addresses_vsg:
type: tosca.nodes.AddressPool
@@ -50,11 +54,11 @@
view_url: /admin/cord/vsgservice/$id$/
backend_network_label: hpc_client
public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
- private_key_fn: /opt/xos/synchronizers/vcpe/vcpe_private_key
+ private_key_fn: /opt/xos/services/vsg/keys/vsg_rsa
# node_label: label_vsg
replaces: service_vsg
artifacts:
- pubkey: /opt/xos/synchronizers/vcpe/vcpe_public_key
+ pubkey: /opt/xos/services/vsg/keys/vsg_rsa.pub
service#vrouter:
type: tosca.nodes.VRouterService
diff --git a/xos/configurations/cord-pod/disable-onboarding.yaml b/xos/configurations/cord-pod/disable-onboarding.yaml
new file mode 100644
index 0000000..0dd1ded
--- /dev/null
+++ b/xos/configurations/cord-pod/disable-onboarding.yaml
@@ -0,0 +1,17 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+ - custom_types/xos.yaml
+
+topology_template:
+ node_templates:
+ xos:
+ type: tosca.nodes.XOS
+ properties:
+ no-create: true
+ no-delete: true
+ no-update: true
+ enable_build: false
+
diff --git a/xos/configurations/cord-pod/docker-compose-bootstrap.yml b/xos/configurations/cord-pod/docker-compose-bootstrap.yml
index 9f17c42..83bb685 100644
--- a/xos/configurations/cord-pod/docker-compose-bootstrap.yml
+++ b/xos/configurations/cord-pod/docker-compose-bootstrap.yml
@@ -40,52 +40,52 @@
max-size: "100k"
max-file: "5"
-xos_synchronizer_onos:
- image: xosproject/xos-synchronizer-openstack
- command: bash -c "python /opt/xos/synchronizers/onos/onos-synchronizer.py -C /opt/xos/synchronizers/onos/onos_synchronizer_config"
- labels:
- org.xosproject.kind: synchronizer
- org.xosproject.target: onos
- links:
- - xos_db
- volumes:
- - .:/root/setup:ro
- - ./id_rsa:/opt/xos/synchronizers/onos/onos_key:ro # private key
- log_driver: "json-file"
- log_opt:
- max-size: "100k"
- max-file: "5"
+#xos_synchronizer_onos:
+# image: xosproject/xos-synchronizer-openstack
+# command: bash -c "python /opt/xos/synchronizers/onos/onos-synchronizer.py -C /opt/xos/synchronizers/onos/onos_synchronizer_config"
+# labels:
+# org.xosproject.kind: synchronizer
+# org.xosproject.target: onos
+# links:
+# - xos_db
+# volumes:
+# - .:/root/setup:ro
+# - ./id_rsa:/opt/xos/synchronizers/onos/onos_key:ro # private key
+# log_driver: "json-file"
+# log_opt:
+# max-size: "100k"
+# max-file: "5"
-xos_synchronizer_vcpe:
- image: xosproject/xos-synchronizer-openstack
- command: bash -c "sleep 120; cp /root/setup/node_key /opt/xos/synchronizers/vcpe/; chmod 0600 /opt/xos/synchronizers/vcpe/node_key; python /opt/xos/synchronizers/vcpe/vcpe-synchronizer.py -C /root/setup/files/vcpe_synchronizer_config"
- labels:
- org.xosproject.kind: synchronizer
- org.xosproject.target: vcpe
- links:
- - xos_db
- volumes:
- - .:/root/setup:ro
- - ./id_rsa:/opt/xos/synchronizers/vcpe/vcpe_private_key:ro # private key
- log_driver: "json-file"
- log_opt:
- max-size: "100k"
- max-file: "5"
+#xos_synchronizer_vcpe:
+# image: xosproject/xos-synchronizer-openstack
+# command: bash -c "sleep 120; cp /root/setup/node_key /opt/xos/synchronizers/vcpe/; chmod 0600 /opt/xos/synchronizers/vcpe/node_key; python /opt/xos/synchronizers/vcpe/vcpe-synchronizer.py -C /root/setup/files/vcpe_synchronizer_config"
+# labels:
+# org.xosproject.kind: synchronizer
+# org.xosproject.target: vcpe
+# links:
+# - xos_db
+# volumes:
+# - .:/root/setup:ro
+# - ./id_rsa:/opt/xos/synchronizers/vcpe/vcpe_private_key:ro # private key
+# log_driver: "json-file"
+# log_opt:
+# max-size: "100k"
+# max-file: "5"
-xos_synchronizer_vtn:
- image: xosproject/xos-synchronizer-openstack
- command: bash -c "sleep 120; python /opt/xos/synchronizers/vtn/vtn-synchronizer.py -C /opt/xos/synchronizers/vtn/vtn_synchronizer_config"
- labels:
- org.xosproject.kind: synchronizer
- org.xosproject.target: vtn
- links:
- - xos_db
- volumes:
- - .:/root/setup:ro
- log_driver: "json-file"
- log_opt:
- max-size: "100k"
- max-file: "5"
+#xos_synchronizer_vtn:
+# image: xosproject/xos-synchronizer-openstack
+# command: bash -c "sleep 120; python /opt/xos/synchronizers/vtn/vtn-synchronizer.py -C /opt/xos/synchronizers/vtn/vtn_synchronizer_config"
+# labels:
+# org.xosproject.kind: synchronizer
+# org.xosproject.target: vtn
+# links:
+# - xos_db
+# volumes:
+# - .:/root/setup:ro
+# log_driver: "json-file"
+# log_opt:
+# max-size: "100k"
+# max-file: "5"
xos_synchronizer_monitoring_channel:
image: xosproject/xos-synchronizer-openstack
@@ -103,36 +103,36 @@
max-size: "100k"
max-file: "5"
-xos_synchronizer_vtr:
- image: xosproject/xos-synchronizer-openstack
- command: bash -c "sleep 120; cp /root/setup/node_key /opt/xos/synchronizers/vtr/; chmod 0600 /opt/xos/synchronizers/vtr/node_key; python /opt/xos/synchronizers/vtr/vtr-synchronizer.py -C /root/setup/files/vtr_synchronizer_config"
- labels:
- org.xosproject.kind: synchronizer
- org.xosproject.target: vtr
- links:
- - xos_db
- volumes:
- - .:/root/setup:ro
- - ./id_rsa:/opt/xos/synchronizers/vtr/vcpe_private_key:ro # private key
- log_driver: "json-file"
- log_opt:
- max-size: "100k"
- max-file: "5"
+#xos_synchronizer_vtr:
+# image: xosproject/xos-synchronizer-openstack
+# command: bash -c "sleep 120; cp /root/setup/node_key /opt/xos/synchronizers/vtr/; chmod 0600 /opt/xos/synchronizers/vtr/node_key; python /opt/xos/synchronizers/vtr/vtr-synchronizer.py -C /root/setup/files/vtr_synchronizer_config"
+# labels:
+# org.xosproject.kind: synchronizer
+# org.xosproject.target: vtr
+# links:
+# - xos_db
+# volumes:
+# - .:/root/setup:ro
+# - ./id_rsa:/opt/xos/synchronizers/vtr/vcpe_private_key:ro # private key
+# log_driver: "json-file"
+# log_opt:
+# 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_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
diff --git a/xos/configurations/cord-pod/enable-onboarding.yaml b/xos/configurations/cord-pod/enable-onboarding.yaml
new file mode 100644
index 0000000..b31ac1d
--- /dev/null
+++ b/xos/configurations/cord-pod/enable-onboarding.yaml
@@ -0,0 +1,17 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+ - custom_types/xos.yaml
+
+topology_template:
+ node_templates:
+ xos:
+ type: tosca.nodes.XOS
+ properties:
+ no-create: true
+ no-delete: true
+ no-update: true
+ enable_build: true
+
diff --git a/xos/configurations/cord-pod/files/vcpe_synchronizer_config b/xos/configurations/cord-pod/files/vcpe_synchronizer_config
index 46ee0c3..9da6ede 100644
--- a/xos/configurations/cord-pod/files/vcpe_synchronizer_config
+++ b/xos/configurations/cord-pod/files/vcpe_synchronizer_config
@@ -23,10 +23,10 @@
[observer]
name=vcpe
-dependency_graph=/opt/xos/synchronizers/vcpe/model-deps
-steps_dir=/opt/xos/synchronizers/vcpe/steps
-sys_dir=/opt/xos/synchronizers/vcpe/sys
-deleters_dir=/opt/xos/synchronizers/vcpe/deleters
+dependency_graph=/opt/xos/synchronizers/vsg/model-deps
+steps_dir=/opt/xos/synchronizers/vsg/steps
+sys_dir=/opt/xos/synchronizers/vsg/sys
+deleters_dir=/opt/xos/synchronizers/vsg/deleters
log_file=console
#/var/log/hpc.log
driver=None
diff --git a/xos/configurations/cord-pod/files/vtr_synchronizer_config b/xos/configurations/cord-pod/files/vtr_synchronizer_config
index 2c9140a..223ab00 100644
--- a/xos/configurations/cord-pod/files/vtr_synchronizer_config
+++ b/xos/configurations/cord-pod/files/vtr_synchronizer_config
@@ -36,7 +36,7 @@
# set proxy_ssh to false on cloudlab
full_setup=True
proxy_ssh=True
-proxy_ssh_key=/opt/xos/synchronizers/vtr/node_key
+proxy_ssh_key=/root/setup/node_key
proxy_ssh_user=root
[networking]
diff --git a/xos/configurations/cord-pod/synchronizers.yaml b/xos/configurations/cord-pod/synchronizers.yaml
new file mode 100644
index 0000000..02035e3
--- /dev/null
+++ b/xos/configurations/cord-pod/synchronizers.yaml
@@ -0,0 +1,19 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: This recipe provides additional configuration for the onboarded services.
+
+imports:
+ - custom_types/xos.yaml
+
+topology_template:
+ node_templates:
+ servicecontroller#vsg:
+ type: tosca.nodes.ServiceController
+ properties:
+ no-create: true
+ synchronizer_config: /root/setup/files/vcpe_synchronizer_config
+ servicecontroller#vtr:
+ type: tosca.nodes.ServiceController
+ properties:
+ no-create: true
+ synchronizer_config: /root/setup/files/vtr_synchronizer_config
diff --git a/xos/configurations/cord-pod/xos.yaml b/xos/configurations/cord-pod/xos.yaml
index 06b5eb5..95cbf18 100644
--- a/xos/configurations/cord-pod/xos.yaml
+++ b/xos/configurations/cord-pod/xos.yaml
@@ -54,25 +54,25 @@
node: xos
relationship: tosca.relationships.UsedByXOS
- /opt/xos/synchronizers/onos/onos_key.pub:
- type: tosca.nodes.XOSVolume
- properties:
- host_path: { path_join: [ SELF, CONFIG_DIR, id_rsa.pub, ENV_VAR ] }
- read_only: true
- requirements:
- - xos:
- node: xos
- relationship: tosca.relationships.UsedByXOS
+# /opt/xos/synchronizers/onos/onos_key.pub:
+# type: tosca.nodes.XOSVolume
+# properties:
+# host_path: { path_join: [ SELF, CONFIG_DIR, id_rsa.pub, ENV_VAR ] }
+# read_only: true
+# requirements:
+# - xos:
+# node: xos
+# relationship: tosca.relationships.UsedByXOS
- /opt/xos/synchronizers/vcpe/vcpe_public_key:
- type: tosca.nodes.XOSVolume
- properties:
- host_path: { path_join: [ SELF, CONFIG_DIR, id_rsa.pub, ENV_VAR ] }
- read_only: true
- requirements:
- - xos:
- node: xos
- relationship: tosca.relationships.UsedByXOS
+# /opt/xos/synchronizers/vcpe/vcpe_public_key:
+# type: tosca.nodes.XOSVolume
+# properties:
+# host_path: { path_join: [ SELF, CONFIG_DIR, id_rsa.pub, ENV_VAR ] }
+# read_only: true
+# requirements:
+# - xos:
+# node: xos
+# relationship: tosca.relationships.UsedByXOS
/opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key:
type: tosca.nodes.XOSVolume
diff --git a/xos/configurations/frontend/Makefile b/xos/configurations/frontend/Makefile
index 46f39bf..8845196 100644
--- a/xos/configurations/frontend/Makefile
+++ b/xos/configurations/frontend/Makefile
@@ -3,23 +3,33 @@
DOCKER_COMPOSE_YML=./onboarding-docker-compose/docker-compose.yml
BOOTSTRAP_YML=./docker-compose-bootstrap.yml
DOCKER_PROJECT=frontend
+XOS_BOOTSTRAP_PORT=9998
+XOS_UI_PORT=9999
-frontend: prereqs bootstrap
- bash ../common/wait_for_xos_port.sh 9999
- sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
- sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
- sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/frontend/sample.yaml
+frontend: prereqs bootstrap onboarding frontendconfig
prereqs:
sudo make -f ../common/Makefile.prereqs
bootstrap:
+ echo "[BOOTSTRAP]"
sudo rm -f onboarding-docker-compose/docker-compose.yml
- sudo rm -f docker-compose.yml
sudo docker-compose -p $(DOCKER_PROJECT) -f docker-compose-bootstrap.yml up -d
- bash ../common/wait_for_xos_port.sh 9998
+ bash ../common/wait_for_xos_port.sh $(XOS_BOOTSTRAP_PORT)
sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run -e CONFIG_DIR=$(CONFIG_DIR) xos_bootstrap_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/frontend/xos.yaml
+onboarding:
+ echo "[ONBOARDING]"
+ # on-board any services here
+ bash ../common/wait_for_onboarding_ready.sh $(XOS_BOOTSTRAP_PORT) xos
+ bash ../common/wait_for_xos_port.sh $(XOS_UI_PORT)
+
+frontendconfig:
+ echo "[FRONTENDCONFIG]"
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/frontend/sample.yaml
+
containers:
cd ../../../containers/xos; make devel
cd ../../../containers/synchronizer; make
@@ -50,15 +60,29 @@
sudo docker exec frontend_xos_1 rm -f /opt/xos/xos_configuration/xos_mcord_config
sudo docker exec frontend_xos_1 rm -f /opt/xos/xos_configuration/xos_cord_config
-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
+mock-cord-pod: onboard-cord-pod
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/fixtures.yaml
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/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 /opt/xos/configurations/cord-pod/cord-vtn-vsg.yaml
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui 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
-
+onboard-cord-pod:
+ #sudo cp id_rsa key_import/vsg_rsa
+ #sudo cp id_rsa.pub key_import/vsg_rsa.pub
+ #sudo cp id_rsa key_import/volt_rsa
+ #sudo cp id_rsa.pub key_import/volt_rsa.pub
+ sudo bash -c "echo somekey > key_import/vsg_rsa"
+ sudo bash -c "echo somekey > key_import/vsg_rsa.pub"
+ sudo bash -c "echo somekey > key_import/volt_rsa"
+ sudo bash -c "echo somekey > key_import/volt_rsa.pub"
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/volt/volt-onboard.yaml
+ sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/vsg/vsg-onboard.yaml
+ bash ../common/wait_for_onboarding_ready.sh 9998 services/volt
+ bash ../common/wait_for_onboarding_ready.sh 9998 services/vsg
+ bash ../common/wait_for_onboarding_ready.sh $(XOS_BOOTSTRAP_PORT) xos
+ bash ../common/wait_for_xos_port.sh $(XOS_UI_PORT)
mock-mcord:
# check this
diff --git a/xos/configurations/frontend/docker-compose-bootstrap.yml b/xos/configurations/frontend/docker-compose-bootstrap.yml
index 3975893..00a43f3 100644
--- a/xos/configurations/frontend/docker-compose-bootstrap.yml
+++ b/xos/configurations/frontend/docker-compose-bootstrap.yml
@@ -17,7 +17,7 @@
xos_synchronizer_onboarding:
image: xosproject/xos-synchronizer-onboarding
command: bash -c "cd /opt/xos/synchronizers/onboarding; ./run.sh"
- #command: sleep 86400
+# command: sleep 86400
labels:
org.xosproject.kind: synchronizer
org.xosproject.target: onboarding
diff --git a/xos/configurations/frontend/xos.yaml b/xos/configurations/frontend/xos.yaml
index 8b286cd..3153e95 100644
--- a/xos/configurations/frontend/xos.yaml
+++ b/xos/configurations/frontend/xos.yaml
@@ -13,6 +13,7 @@
ui_port: 9999
bootstrap_ui_port: 9998
docker_project_name: frontend
+ frontend_only: true
/opt/xos/xos_configuration/xos_common_config:
type: tosca.nodes.XOSVolume
diff --git a/xos/core/admin.py b/xos/core/admin.py
index 28ab2e8..b2206a6 100644
--- a/xos/core/admin.py
+++ b/xos/core/admin.py
@@ -1062,7 +1062,7 @@
class ServiceControllerAdmin(XOSBaseAdmin):
list_display = ("backend_status_icon", "name",)
list_display_links = ('backend_status_icon', 'name',)
- fieldList = ["backend_status_text", "name", "xos", "base_url"]
+ fieldList = ["backend_status_text", "name", "xos", "base_url", "synchronizer_run", "synchronizer_config"]
fieldsets = [
(None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
inlines = [ServiceControllerResourceInline]
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
index c871c7e..83b827c 100644
--- a/xos/core/models/service.py
+++ b/xos/core/models/service.py
@@ -70,6 +70,9 @@
name = StrippedCharField(max_length=30, help_text="Service Name")
base_url = StrippedCharField(max_length=1024, help_text="Base URL, allows use of relative URLs for resources", null=True, blank=True)
+ synchronizer_run = StrippedCharField(max_length=1024, help_text="synchronizer run command", null=True, blank=True)
+ synchronizer_config = StrippedCharField(max_length=1024, help_text="synchronizer config file", null=True, blank=True)
+
def __unicode__(self): return u'%s' % (self.name)
def save(self, *args, **kwargs):
@@ -83,6 +86,7 @@
class ServiceControllerResource(PlCoreBase):
KIND_CHOICES = (('models', 'Models'),
('admin', 'Admin'),
+ ('admin_template', 'Admin Template'),
('django_library', 'Django Library'),
('synchronizer', 'Synchronizer'),
('rest_service', 'REST API (service)'),
@@ -102,6 +106,7 @@
help_text="The Service Controller this resource is associated with")
name = StrippedCharField(max_length=30, help_text="Object Name")
+ subdirectory = StrippedCharField(max_length=1024, help_text="optional subdirectory", null=True, blank=True)
kind = StrippedCharField(choices=KIND_CHOICES, max_length=30)
format = StrippedCharField(choices=FORMAT_CHOICES, max_length=30)
url = StrippedCharField(max_length=1024, help_text="URL of resource", null=True, blank=True)
diff --git a/xos/core/models/xosmodel.py b/xos/core/models/xosmodel.py
index 4942241..01c9514 100644
--- a/xos/core/models/xosmodel.py
+++ b/xos/core/models/xosmodel.py
@@ -14,6 +14,7 @@
db_container_name = StrippedCharField(max_length=200, help_text="name of XOS db container", default="xos_db")
docker_project_name = StrippedCharField(max_length=200, help_text="docker project name")
enable_build = models.BooleanField(help_text="True if Onboarding Synchronizer should build XOS as necessary", default=True)
+ frontend_only = models.BooleanField(help_text="If True, XOS will not start synchronizer containers", default=False)
def __unicode__(self): return u'%s' % (self.name)
diff --git a/xos/core/xoslib/methods/ceilometerview.py b/xos/core/xoslib/methods/ceilometerview._unused
similarity index 100%
rename from xos/core/xoslib/methods/ceilometerview.py
rename to xos/core/xoslib/methods/ceilometerview._unused
diff --git a/xos/core/xoslib/methods/cordsubscriber.py b/xos/core/xoslib/methods/cordsubscriber._unused
similarity index 87%
rename from xos/core/xoslib/methods/cordsubscriber.py
rename to xos/core/xoslib/methods/cordsubscriber._unused
index b69b09d..8fc88e0 100644
--- a/xos/core/xoslib/methods/cordsubscriber.py
+++ b/xos/core/xoslib/methods/cordsubscriber._unused
@@ -9,7 +9,7 @@
from core.models import *
from django.forms import widgets
from django.conf.urls import patterns, url
-from services.cord.models import VOLTTenant, VBNGTenant, CordSubscriberRoot
+from services.volt.models import VOLTTenant, CordSubscriberRoot
from core.xoslib.objects.cordsubscriber import CordSubscriber
from plus import PlusSerializerMixin, XOSViewSet
from django.shortcuts import get_object_or_404
@@ -208,7 +208,7 @@
patterns.append( url("^rs/subidlookup/(?P<ssid>[0-9\-]+)/$", self.as_view({"get": "ssiddetail"}), name="ssiddetail") )
patterns.append( url("^rs/subidlookup/$", self.as_view({"get": "ssidlist"}), name="ssidlist") )
- patterns.append( url("^rs/vbng_mapping/$", self.as_view({"get": "get_vbng_mapping"}), name="vbng_mapping") )
+ #patterns.append( url("^rs/vbng_mapping/$", self.as_view({"get": "get_vbng_mapping"}), name="vbng_mapping") )
return patterns
@@ -367,47 +367,14 @@
return Response( ssidmap[0] )
- def get_vbng_mapping(self, request):
- object_list = VBNGTenant.get_tenant_objects().all()
+ #def get_vbng_mapping(self, request):
+ # object_list = VBNGTenant.get_tenant_objects().all()
+ #
+ # mappings = []
+ # for vbng in object_list:
+ # if vbng.mapped_ip and vbng.routeable_subnet:
+ # mappings.append( {"private_ip": vbng.mapped_ip, "routeable_subnet": vbng.routeable_subnet, "mac": vbng.mapped_mac, "hostname": vbng.mapped_hostname} )
+ #
+ # return Response( {"vbng_mapping": mappings} )
- mappings = []
- for vbng in object_list:
- if vbng.mapped_ip and vbng.routeable_subnet:
- mappings.append( {"private_ip": vbng.mapped_ip, "routeable_subnet": vbng.routeable_subnet, "mac": vbng.mapped_mac, "hostname": vbng.mapped_hostname} )
- return Response( {"vbng_mapping": mappings} )
-
-class CordDebugIdSerializer(serializers.ModelSerializer, PlusSerializerMixin):
- # Swagger is failing because CordDebugViewSet has neither a model nor
- # a serializer_class. Stuck this in here as a placeholder for now.
- id = ReadOnlyField()
- class Meta:
- model = CordSubscriber
-
-class CordDebugViewSet(XOSViewSet):
- base_name = "cord_debug"
- method_name = "rs/cord_debug"
- method_kind = "viewset"
- serializer_class = CordDebugIdSerializer
-
- @classmethod
- def get_urlpatterns(self):
- patterns = []
- patterns.append( url("^rs/cord_debug/vbng_dump/$", self.as_view({"get": "get_vbng_dump"}), name="vbng_dump"))
- return patterns
-
- # contact vBNG service and dump current list of mappings
- def get_vbng_dump(self, request, pk=None):
- result=subprocess.check_output(["curl", "http://10.0.3.136:8181/onos/virtualbng/privateip/map"])
- if request.GET.get("theformat",None)=="text":
- from django.http import HttpResponse
- result = json.loads(result)["map"]
-
- lines = []
- for row in result:
- for k in row.keys():
- lines.append( "%s %s" % (k, row[k]) )
-
- return HttpResponse("\n".join(lines), content_type="text/plain")
- else:
- return Response( {"vbng_dump": json.loads(result)["map"] } )
diff --git a/xos/core/xoslib/methods/monitoringchannel.py b/xos/core/xoslib/methods/monitoringchannel._unused
similarity index 100%
rename from xos/core/xoslib/methods/monitoringchannel.py
rename to xos/core/xoslib/methods/monitoringchannel._unused
diff --git a/xos/core/xoslib/methods/truckroll.py b/xos/core/xoslib/methods/truckroll.py
deleted file mode 100644
index 917a676..0000000
--- a/xos/core/xoslib/methods/truckroll.py
+++ /dev/null
@@ -1,92 +0,0 @@
-from rest_framework.decorators import api_view
-from rest_framework.response import Response
-from rest_framework.reverse import reverse
-from rest_framework import serializers
-from rest_framework import generics
-from rest_framework import status
-from core.models import *
-from django.forms import widgets
-from services.cord.models import CordSubscriberRoot
-from services.vtr.models import VTRTenant, VTRService
-from plus import PlusSerializerMixin
-from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
-
-if hasattr(serializers, "ReadOnlyField"):
- # rest_framework 3.x
- ReadOnlyField = serializers.ReadOnlyField
-else:
- # rest_framework 2.x
- ReadOnlyField = serializers.Field
-
-def get_default_vtr_service():
- vtr_services = VTRService.get_service_objects().all()
- if vtr_services:
- return vtr_services[0].id
- return None
-
-class VTRTenantIdSerializer(serializers.ModelSerializer, PlusSerializerMixin):
- id = ReadOnlyField()
- target_id = serializers.IntegerField()
- test = serializers.CharField()
- scope = serializers.CharField()
- argument = serializers.CharField(required=False)
- provider_service = serializers.PrimaryKeyRelatedField(queryset=VTRService.get_service_objects().all(), default=get_default_vtr_service)
- result = serializers.CharField(required=False)
- result_code = serializers.CharField(required=False)
- backend_status = ReadOnlyField()
-
- humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
- is_synced = serializers.SerializerMethodField("isSynced")
-
- class Meta:
- model = VTRTenant
- fields = ('humanReadableName', 'id', 'provider_service', 'target_id', 'scope', 'test', 'argument', 'result', 'result_code', 'is_synced', 'backend_status' )
-
- def getHumanReadableName(self, obj):
- return obj.__unicode__()
-
- def isSynced(self, obj):
- return (obj.enacted is not None) and (obj.enacted >= obj.updated)
-
-class VTRTenantList(XOSListCreateAPIView):
- serializer_class = VTRTenantIdSerializer
-
- method_kind = "list"
- method_name = "truckroll"
-
- def get_queryset(self):
- queryset = VTRTenant.get_tenant_objects().select_related().all()
-
- test = self.request.QUERY_PARAMS.get('test', None)
- if test is not None:
- ids = [x.id for x in queryset if x.get_attribute("test", None)==test]
- queryset = queryset.filter(id__in=ids)
-
- return queryset
-
- def post(self, request, format=None):
- data = request.DATA
-
- existing_obj = None
-# for obj in VTRTenant.get_tenant_objects().all():
-# if (obj.tesst == data.get("test", None)) and (obj.target == data.get("target", None))):
-# existing_obj = obj
-
- if existing_obj:
- serializer = VTRTenantIdSerializer(existing_obj)
- headers = self.get_success_headers(serializer.data)
- return Response( serializer.data, status=status.HTTP_200_OK )
-
- return super(VTRTenantList, self).post(request, format)
-
-class VTRTenantDetail(XOSRetrieveUpdateDestroyAPIView):
- serializer_class = VTRTenantIdSerializer
- queryset = VTRTenant.get_tenant_objects().select_related().all()
-
- method_kind = "detail"
- method_name = "truckroll"
-
-
-
-
-
diff --git a/xos/core/xoslib/methods/volttenant.py b/xos/core/xoslib/methods/volttenant._unused
similarity index 97%
rename from xos/core/xoslib/methods/volttenant.py
rename to xos/core/xoslib/methods/volttenant._unused
index 25559a0..03a2a97 100644
--- a/xos/core/xoslib/methods/volttenant.py
+++ b/xos/core/xoslib/methods/volttenant._unused
@@ -6,7 +6,7 @@
from rest_framework import status
from core.models import *
from django.forms import widgets
-from services.cord.models import VOLTTenant, VOLTService, CordSubscriberRoot
+from services.volt.models import VOLTTenant, VOLTService, CordSubscriberRoot
from plus import PlusSerializerMixin
from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
diff --git a/xos/core/xoslib/methods/vtn.py b/xos/core/xoslib/methods/vtn._unused
similarity index 100%
rename from xos/core/xoslib/methods/vtn.py
rename to xos/core/xoslib/methods/vtn._unused
diff --git a/xos/core/xoslib/objects/cordsubscriber.py b/xos/core/xoslib/objects/cordsubscriber.py
index 681b769..d97bd5a 100644
--- a/xos/core/xoslib/objects/cordsubscriber.py
+++ b/xos/core/xoslib/objects/cordsubscriber.py
@@ -1,23 +1,9 @@
from core.models import Slice, SlicePrivilege, SliceRole, Instance, Site, Node, User
-from services.cord.models import VOLTTenant, CordSubscriberRoot
+from services.volt.models import VOLTTenant, CordSubscriberRoot
from plus import PlusObjectMixin
from operator import itemgetter, attrgetter
from rest_framework.exceptions import APIException
-"""
-import os
-import sys
-sys.path.append("/opt/xos")
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
-import django
-from core.models import *
-from services.hpc.models import *
-from services.cord.models import *
-django.setup()
-from core.xoslib.objects.cordsubscriber import CordSubscriber
-c=CordSubscriber.get_tenant_objects().select_related().all()[0]
-"""
-
class CordSubscriber(CordSubscriberRoot):
class Meta:
proxy = True
diff --git a/xos/core/xoslib/static/js/vendor/ngXosHelpers.js b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
index 174a087..283b8be 100644
--- a/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
+++ b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
@@ -1 +1,2 @@
-"use strict";!function(){angular.module("xos.uiComponents",["chart.js","RecursionHelper"])}();var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(){angular.module("xos.uiComponents").directive("xosSmartTable",function(){return{restrict:"E",scope:{config:"="},template:'\n <div class="row" ng-show="vm.data.length > 0">\n <div class="col-xs-12 text-right">\n <a href="" class="btn btn-success" ng-click="vm.createItem()">\n Add\n </a>\n </div>\n </div>\n <div class="row">\n <div class="col-xs-12 table-responsive">\n <xos-table config="vm.tableConfig" data="vm.data"></xos-table>\n </div>\n </div>\n <div class="panel panel-default" ng-show="vm.detailedItem">\n <div class="panel-heading">\n <div class="row">\n <div class="col-xs-11">\n <h3 class="panel-title" ng-show="vm.detailedItem.id">Update {{vm.config.resource}} {{vm.detailedItem.id}}</h3>\n <h3 class="panel-title" ng-show="!vm.detailedItem.id">Create {{vm.config.resource}} item</h3>\n </div>\n <div class="col-xs-1">\n <a href="" ng-click="vm.cleanForm()">\n <i class="glyphicon glyphicon-remove pull-right"></i>\n </a>\n </div>\n </div>\n </div>\n <div class="panel-body">\n <xos-form config="vm.formConfig" ng-model="vm.detailedItem"></xos-form>\n </div>\n </div>\n <xos-alert config="{type: \'success\', closeBtn: true}" show="vm.responseMsg">{{vm.responseMsg}}</xos-alert>\n <xos-alert config="{type: \'danger\', closeBtn: true}" show="vm.responseErr">{{vm.responseErr}}</xos-alert>\n ',bindToController:!0,controllerAs:"vm",controller:["$injector","LabelFormatter","_","XosFormHelpers",function(e,n,o,t){var i=this;this.responseMsg=!1,this.responseErr=!1,this.tableConfig={columns:[],actions:[{label:"delete",icon:"remove",cb:function(e){i.Resource["delete"]({id:e.id}).$promise.then(function(){o.remove(i.data,function(n){return n.id===e.id}),i.responseMsg=i.config.resource+" with id "+e.id+" successfully deleted"})["catch"](function(n){i.responseErr=n.data.detail||"Error while deleting "+i.config.resource+" with id "+e.id})},color:"red"},{label:"details",icon:"search",cb:function(e){i.detailedItem=e}}],classes:"table table-striped table-bordered table-responsive",filter:"field",order:!0,pagination:{pageSize:10}},this.formConfig={exclude:this.config.hiddenFields,fields:{},formName:this.config.resource+"Form",actions:[{label:"Save",icon:"ok",cb:function(e){var n=void 0,o=!0;e.id?(n=e.$update(),o=!1):n=e.$save(),n.then(function(n){o&&i.data.push(angular.copy(n)),delete i.detailedItem,i.responseMsg=i.config.resource+" with id "+e.id+" successfully saved"})["catch"](function(n){i.responseErr=n.data.detail||"Error while saving "+i.config.resource+" with id "+e.id})},"class":"success"}]},this.cleanForm=function(){delete i.detailedItem},this.createItem=function(){i.detailedItem=new i.Resource},this.Resource=e.get(this.config.resource);var r=function(){i.Resource.query().$promise.then(function(e){if(!e[0])return void(i.data=e);var r=e[0],s=Object.keys(r);o.remove(s,function(e){return"id"===e||"validators"===e}),angular.isArray(i.config.hiddenFields)&&(s=o.difference(s,i.config.hiddenFields));var a=s.map(function(e){return n.format(e)});s.forEach(function(e,n){var o={label:a[n],prop:e};"string"!=typeof r[e]&&"undefined"!=typeof r[e]&&(o.type=_typeof(r[e])),i.tableConfig.columns.push(o)}),s.forEach(function(e,o){i.formConfig.fields[e]={label:n.format(a[o]).replace(":",""),type:t._getFieldFormat(r[e])}}),i.data=e})};r()}]}})}(),function(){angular.module("xos.uiComponents").directive("xosSmartPie",function(){return{restrict:"E",scope:{config:"="},template:'\n <canvas\n class="chart chart-pie {{vm.config.classes}}"\n chart-data="vm.data" chart-labels="vm.labels"\n chart-legend="{{vm.config.legend}}">\n </canvas>\n ',bindToController:!0,controllerAs:"vm",controller:["$injector","$interval","$scope","$timeout","_",function(e,n,o,t,i){var r=this;if(!this.config.resource&&!this.config.data)throw new Error("[xosSmartPie] Please provide a resource or an array of data in the configuration");var s=function(e){return i.groupBy(e,r.config.groupBy)},a=function(e){return i.reduce(Object.keys(e),function(n,o){return n.concat(e[o].length)},[])},l=function(e){return angular.isFunction(r.config.labelFormatter)?r.config.labelFormatter(Object.keys(e)):Object.keys(e)},c=function(e){var n=s(e);r.data=a(n),r.labels=l(n)};this.config.resource?!function(){r.Resource=e.get(r.config.resource);var o=function(){r.Resource.query().$promise.then(function(e){e[0]&&c(e)})};o(),r.config.poll&&n(function(){o()},1e3*r.config.poll)}():o.$watch(function(){return r.config.data},function(e){e&&c(r.config.data)},!0),o.$on("create",function(e,n){console.log("create: "+n.id)}),o.$on("destroy",function(e,n){console.log("destroy: "+n.id)})}]}})}(),function(){angular.module("xos.uiComponents").directive("xosValidation",function(){return{restrict:"E",scope:{field:"=",form:"="},template:'\n <div ng-cloak>\n <xos-alert config="vm.config" show="vm.field.$error.required !== undefined && vm.field.$error.required !== false && (vm.field.$touched || vm.form.$submitted)">\n Field required\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.email !== undefined && vm.field.$error.email !== false && (vm.field.$touched || vm.form.$submitted)">\n This is not a valid email\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.minlength !== undefined && vm.field.$error.minlength !== false && (vm.field.$touched || vm.form.$submitted)">\n Too short\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.maxlength !== undefined && vm.field.$error.maxlength !== false && (vm.field.$touched || vm.form.$submitted)">\n Too long\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.custom !== undefined && vm.field.$error.custom !== false && (vm.field.$touched || vm.form.$submitted)">\n Field invalid\n </xos-alert>\n </div>\n ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:function(){this.config={type:"danger"}}}})}(),function(){angular.module("xos.uiComponents").directive("xosTable",function(){return{restrict:"E",scope:{data:"=",config:"="},template:'\n <div ng-show="vm.data.length > 0 && vm.loader == false">\n <div class="row" ng-if="vm.config.filter == \'fulltext\'">\n <div class="col-xs-12">\n <input\n class="form-control"\n placeholder="Type to search.."\n type="text"\n ng-model="vm.query"/>\n </div>\n </div>\n <table ng-class="vm.classes" ng-hide="vm.data.length == 0">\n <thead>\n <tr>\n <th ng-repeat="col in vm.columns">\n {{col.label}}\n <span ng-if="vm.config.order">\n <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = false">\n <i class="glyphicon glyphicon-chevron-up"></i>\n </a>\n <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = true">\n <i class="glyphicon glyphicon-chevron-down"></i>\n </a>\n </span>\n </th>\n <th ng-if="vm.config.actions">Actions:</th>\n </tr>\n </thead>\n <tbody ng-if="vm.config.filter == \'field\'">\n <tr>\n <td ng-repeat="col in vm.columns">\n <input\n ng-if="col.type !== \'boolean\'"\n class="form-control"\n placeholder="Type to search by {{col.label}}"\n type="text"\n ng-model="vm.query[col.prop]"/>\n <select\n ng-if="col.type === \'boolean\'"\n class="form-control"\n ng-model="vm.query[col.prop]">\n <option value="">-</option>\n <option value="true">True</option>\n <option value="false">False</option>\n </select>\n </td>\n <td ng-if="vm.config.actions"></td>\n </tr>\n </tbody>\n <tbody>\n <tr ng-repeat="item in vm.data | filter:vm.query | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">\n <td ng-repeat="col in vm.columns" link-wrapper>\n <span ng-if="!col.type">{{item[col.prop]}}</span>\n <span ng-if="col.type === \'boolean\'">\n <i class="glyphicon"\n ng-class="{\'glyphicon-ok\': item[col.prop], \'glyphicon-remove\': !item[col.prop]}">\n </i>\n </span>\n <span ng-if="col.type === \'date\'">\n {{item[col.prop] | date:\'H:mm MMM d, yyyy\'}}\n </span>\n <span ng-if="col.type === \'array\'">\n {{item[col.prop] | arrayToList}}\n </span>\n <span ng-if="col.type === \'object\'">\n <dl class="dl-horizontal">\n <span ng-repeat="(k,v) in item[col.prop]">\n <dt>{{k}}</dt>\n <dd>{{v}}</dd>\n </span>\n </dl>\n </span>\n <span ng-if="col.type === \'custom\'">\n {{col.formatter(item)}}\n </span>\n <span ng-if="col.type === \'icon\'">\n <i class="glyphicon glyphicon-{{col.formatter(item)}}">\n </i>\n </span>\n </td>\n <td ng-if="vm.config.actions">\n <a href=""\n ng-repeat="action in vm.config.actions"\n ng-click="action.cb(item)"\n title="{{action.label}}">\n <i\n class="glyphicon glyphicon-{{action.icon}}"\n style="color: {{action.color}};"></i>\n </a>\n </td>\n </tr>\n </tbody>\n </table>\n <xos-pagination\n ng-if="vm.config.pagination"\n page-size="vm.config.pagination.pageSize"\n total-elements="vm.data.length"\n change="vm.goToPage">\n </xos-pagination>\n </div>\n <div ng-show="(vm.data.length == 0 || !vm.data) && vm.loader == false">\n <xos-alert config="{type: \'info\'}">\n No data to show.\n </xos-alert>\n </div>\n <div ng-show="vm.loader == true">\n <div class="loader"></div>\n </div>\n ',bindToController:!0,controllerAs:"vm",controller:["_","$scope",function(e,n){var o=this;if(this.loader=!0,n.$watch(function(){return o.data},function(e){angular.isDefined(e)&&(o.loader=!1)}),!this.config)throw new Error('[xosTable] Please provide a configuration via the "config" attribute');if(!this.config.columns)throw new Error("[xosTable] Please provide a columns list in the configuration");this.config.order&&angular.isObject(this.config.order)&&(this.reverse=this.config.order.reverse||!1,this.orderBy=this.config.order.field||"id");var t=e.filter(this.config.columns,{type:"custom"});angular.isArray(t)&&t.length>0&&e.forEach(t,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided a custom field type, a formatter function should provided too.")});var i=e.filter(this.config.columns,{type:"icon"});angular.isArray(i)&&i.length>0&&e.forEach(i,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided an icon field type, a formatter function should provided too.")});var r=e.filter(this.config.columns,function(e){return angular.isDefined(e.link)});angular.isArray(r)&&r.length>0&&e.forEach(r,function(e){if(!angular.isFunction(e.link))throw new Error("[xosTable] The link property should be a function.")}),this.columns=this.config.columns,this.classes=this.config.classes||"table table-striped table-bordered",this.config.actions,this.config.pagination&&(this.currentPage=0,this.goToPage=function(e){o.currentPage=e})}]}}).filter("arrayToList",function(){return function(e){return angular.isArray(e)?e.join(", "):e}}).directive("linkWrapper",function(){return{restrict:"A",transclude:!0,template:'\n <a ng-if="col.link" href="{{col.link(item)}}">\n <div ng-transclude></div>\n </a>\n <div ng-transclude ng-if="!col.link"></div>\n '}})}(),function(){angular.module("xos.uiComponents").directive("xosPagination",function(){return{restrict:"E",scope:{pageSize:"=",totalElements:"=",change:"="},template:'\n <div class="row" ng-if="vm.pageList.length > 1">\n <div class="col-xs-12 text-center">\n <ul class="pagination">\n <li\n ng-click="vm.goToPage(vm.currentPage - 1)"\n ng-class="{disabled: vm.currentPage == 0}">\n <a href="" aria-label="Previous">\n <span aria-hidden="true">«</span>\n </a>\n </li>\n <li ng-repeat="i in vm.pageList" ng-class="{active: i === vm.currentPage}">\n <a href="" ng-click="vm.goToPage(i)">{{i + 1}}</a>\n </li>\n <li\n ng-click="vm.goToPage(vm.currentPage + 1)"\n ng-class="{disabled: vm.currentPage == vm.pages - 1}">\n <a href="" aria-label="Next">\n <span aria-hidden="true">»</span>\n </a>\n </li>\n </ul>\n </div>\n </div>\n ',bindToController:!0,controllerAs:"vm",controller:["$scope",function(e){var n=this;this.currentPage=0,this.goToPage=function(e){0>e||e===n.pages||(n.currentPage=e,n.change(e))},this.createPages=function(e){for(var n=[],o=0;e>o;o++)n.push(o);return n},e.$watch(function(){return n.totalElements},function(){n.totalElements&&(n.pages=Math.ceil(n.totalElements/n.pageSize),n.pageList=n.createPages(n.pages))})}]}}).filter("pagination",function(){return function(e,n){return e&&angular.isArray(e)?(n=parseInt(n,10),e.slice(n)):e}})}(),function(){angular.module("xos.uiComponents").directive("xosForm",function(){return{restrict:"E",scope:{config:"=",ngModel:"="},template:'\n <ng-form name="vm.{{vm.config.formName || \'form\'}}">\n <div class="form-group" ng-repeat="(name, field) in vm.formField">\n <xos-field name="name" field="field" ng-model="vm.ngModel[name]"></xos-field>\n <xos-validation field="vm[vm.config.formName || \'form\'][name]" form="vm[vm.config.formName || \'form\']"></xos-validation>\n </div>\n <div class="form-group" ng-if="vm.config.actions">\n <button role="button" href=""\n ng-repeat="action in vm.config.actions"\n ng-click="action.cb(vm.ngModel)"\n class="btn btn-{{action.class}}"\n title="{{action.label}}">\n <i class="glyphicon glyphicon-{{action.icon}}"></i>\n {{action.label}}\n </button>\n </div>\n </ng-form>\n ',bindToController:!0,controllerAs:"vm",controller:["$scope","$log","_","XosFormHelpers",function(e,n,o,t){var i=this;if(!this.config)throw new Error('[xosForm] Please provide a configuration via the "config" attribute');if(!this.config.actions)throw new Error("[xosForm] Please provide an action list in the configuration");this.excludedField=["id","validators","created","updated","deleted","backend_status"],this.config&&this.config.exclude&&(this.excludedField=this.excludedField.concat(this.config.exclude)),this.formField=[],e.$watch(function(){return i.ngModel},function(e){if(i.formField={},e){var n=o.difference(Object.keys(e),i.excludedField),r=t.parseModelField(n);i.formField=t.buildFormStructure(r,i.config.fields,e)}})}]}})}(),function(){angular.module("xos.uiComponents").directive("xosField",["RecursionHelper",function(e){return{restrict:"E",scope:{name:"=",field:"=",ngModel:"="},template:'\n <label ng-if="vm.field.type !== \'object\'">{{vm.field.label}}</label>\n <input\n ng-if="vm.field.type !== \'boolean\' && vm.field.type !== \'object\' && vm.field.type !== \'select\'"\n type="{{vm.field.type}}"\n name="{{vm.name}}"\n class="form-control"\n ng-model="vm.ngModel"\n ng-minlength="vm.field.validators.minlength || 0"\n ng-maxlength="vm.field.validators.maxlength || 2000"\n ng-required="vm.field.validators.required || false" />\n <select class="form-control" ng-if ="vm.field.type === \'select\'"\n name = "{{vm.name}}"\n ng-options="item.id as item.label for item in vm.field.options track by item.id"\n ng-model="vm.ngModel"\n ng-required="vm.field.validators.required || false">\n </select>\n <span class="boolean-field" ng-if="vm.field.type === \'boolean\'">\n <button\n class="btn btn-success"\n ng-show="vm.ngModel"\n ng-click="vm.ngModel = false">\n <i class="glyphicon glyphicon-ok"></i>\n </button>\n <button\n class="btn btn-danger"\n ng-show="!vm.ngModel"\n ng-click="vm.ngModel = true">\n <i class="glyphicon glyphicon-remove"></i>\n </button>\n </span>\n <div\n class="panel panel-default object-field"\n ng-if="vm.field.type == \'object\' && (!vm.isEmptyObject(vm.ngModel) || !vm.isEmptyObject(vm.field.properties))"\n >\n <div class="panel-heading">{{vm.field.label}}</div>\n <div class="panel-body">\n <div ng-if="!vm.field.properties" ng-repeat="(k, v) in vm.ngModel">\n <xos-field\n name="k"\n field="{label: vm.formatLabel(k), type: vm.getType(v)}"\n ng-model="v">\n </xos-field>\n </div>\n <div ng-if="vm.field.properties" ng-repeat="(k, v) in vm.field.properties">\n <xos-field\n name="k"\n field="{\n label: v.label || vm.formatLabel(k),\n type: v.type,\n validators: v.validators\n }"\n ng-model="vm.ngModel[k]">\n </xos-field>\n </div>\n </div>\n </div>\n ',bindToController:!0,controllerAs:"vm",compile:function(n){return e.compile(n)},controller:["$attrs","XosFormHelpers","LabelFormatter",function(e,n,o){if(!this.name)throw new Error("[xosField] Please provide a field name");if(!this.field)throw new Error("[xosField] Please provide a field definition");if(!this.field.type)throw new Error("[xosField] Please provide a type in the field definition");if(!e.ngModel)throw new Error("[xosField] Please provide an ng-model");this.getType=n._getFieldFormat,this.formatLabel=o.format,this.isEmptyObject=function(e){return e?0===Object.keys(e).length:!0}}]}}])}(),function(){angular.module("xos.uiComponents").directive("xosAlert",function(){return{restrict:"E",scope:{config:"=",show:"=?"},template:'\n <div ng-cloak class="alert alert-{{vm.config.type}}" ng-hide="!vm.show">\n <button type="button" class="close" ng-if="vm.config.closeBtn" ng-click="vm.dismiss()">\n <span aria-hidden="true">×</span>\n </button>\n <p ng-transclude></p>\n </div>\n ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:["$timeout",function(e){var n=this;if(!this.config)throw new Error('[xosAlert] Please provide a configuration via the "config" attribute');this.show=this.show!==!1,this.dismiss=function(){n.show=!1},this.config.autoHide&&!function(){var o=e(function(){n.dismiss(),e.cancel(o)},n.config.autoHide)}()}]}})}(),function(){function e(){var e=function(e){return e.split("_").join(" ").trim()},n=function(e){return e.split(/(?=[A-Z])/).map(function(e){return e.toLowerCase()}).join(" ")},o=function(e){return e.slice(0,1).toUpperCase()+e.slice(1)},t=function(t){return t=e(t),t=n(t),t=o(t).replace(/\s\s+/g," ")+":",t.replace("::",":")};return{_formatByUnderscore:e,_formatByUppercase:n,_capitalize:o,format:t}}angular.module("xos.uiComponents").factory("LabelFormatter",e)}();var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(){angular.module("xos.uiComponents").service("XosFormHelpers",["_","LabelFormatter",function(e,n){var o=this;this._isEmail=function(e){var n=/(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;return n.test(e)},this._getFieldFormat=function(n){return angular.isArray(n)?"array":e.isDate(n)||!Number.isNaN(Date.parse(n))&&new Date(n).getTime()>6311808e5?"date":"boolean"==typeof n?"boolean":o._isEmail(n)?"email":"string"==typeof n||null===n?"text":"undefined"==typeof n?"undefined":_typeof(n)},this.buildFormStructure=function(t,i,r){return t=angular.extend(t,i),i=i||{},e.reduce(Object.keys(t),function(e,t){return e[t]={label:i[t]&&i[t].label?i[t].label+":":n.format(t),type:i[t]&&i[t].type?i[t].type:o._getFieldFormat(r[t]),validators:i[t]&&i[t].validators?i[t].validators:{},hint:i[t]&&i[t].hint?i[t].hint:""},i[t]&&i[t].options&&(e[t].options=i[t].options),i[t]&&i[t].properties&&(e[t].properties=i[t].properties),"date"===e[t].type&&(r[t]=new Date(r[t])),"number"===e[t].type&&(r[t]=parseInt(r[t],10)),e},{})},this.parseModelField=function(n){return e.reduce(n,function(e,n){return e[n]={},e},{})}}])}(),function(){function e(e,n,o){e.interceptors.push("SetCSRFToken"),n.startSymbol("{$"),n.endSymbol("$}"),o.defaults.stripTrailingSlashes=!1}e.$inject=["$httpProvider","$interpolateProvider","$resourceProvider"],angular.module("bugSnag",[]).factory("$exceptionHandler",function(){return function(e,n){window.Bugsnag?Bugsnag.notifyException(e,{diagnostics:{cause:n}}):console.error(e,n,e.stack)}}),angular.module("xos.helpers",["ngCookies","ngResource","ngAnimate","bugSnag","xos.uiComponents"]).config(e).factory("_",["$window",function(e){return e._}])}(),function(){angular.module("xos.helpers").service("vSG-Collection",["$resource",function(e){return e("/api/service/vsg/")}])}(),function(){angular.module("xos.helpers").service("vOLT-Collection",["$resource",function(e){return e("/api/tenant/cord/volt/:volt_id/",{volt_id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Login",["$resource",function(e){return e("/api/utility/login/")}]).service("Logout",["$resource",function(e){return e("/api/utility/logout/")}])}(),function(){angular.module("xos.helpers").service("Users",["$resource",function(e){return e("/api/core/users/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Truckroll",["$resource",function(e){return e("/api/tenant/truckroll/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Tenants",["$resource",function(e){return e("/api/core/tenants/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Subscribers",["$resource",function(e){return e("/api/tenant/cord/subscriber/:id/",{id:"@id"},{update:{method:"PUT"},"View-a-Subscriber-Features-Detail":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/"},"Read-Subscriber-uplink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Update-Subscriber-uplink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Read-Subscriber-downlink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Update-Subscriber-downlink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Read-Subscriber-cdn":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Update-Subscriber-cdn":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Read-Subscriber-uverse":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Update-Subscriber-uverse":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Read-Subscriber-status":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"},"Update-Subscriber-status":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"}})}])}(),function(){angular.module("xos.helpers").service("SlicesPlus",["$http","$q",function(e,n){this.query=function(o){var t=n.defer();return e.get("/api/utility/slicesplus/",{params:o}).then(function(e){t.resolve(e.data)})["catch"](function(e){t.reject(e.data)}),{$promise:t.promise}},this.get=function(o,t){var i=n.defer();return e.get("/api/utility/slicesplus/"+o,{params:t}).then(function(e){i.resolve(e.data)})["catch"](function(e){i.reject(e.data)}),{$promise:i.promise}}}])}(),function(){angular.module("xos.helpers").service("Slices",["$resource",function(e){return e("/api/core/slices/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Sites",["$resource",function(e){return e("/api/core/sites/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Services",["$resource",function(e){return e("/api/core/services/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("ONOS-Services-Collection",["$resource",function(e){return e("/api/service/onos/")}])}(),function(){angular.module("xos.helpers").service("ONOS-App-Collection",["$resource",function(e){return e("/api/tenant/onos/app/")}])}(),function(){angular.module("xos.helpers").service("Nodes",["$resource",function(e){return e("/api/core/nodes/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Networks",["$resource",function(e){return e("/api/core/networks/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Instances",["$resource",function(e){return e("/api/core/instances/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Flavors",["$resource",function(e){return e("/api/core/flavors/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Example-Services-Collection",["$resource",function(e){return e("/api/service/exampleservice/")}])}(),function(){angular.module("xos.helpers").service("Deployments",["$resource",function(e){return e("/api/core/deployments/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("XosUserPrefs",["$cookies",function(e){var n=this,o=e.get("xosUserPrefs")?JSON.parse(e.get("xosUserPrefs")):{};this.getAll=function(){return o=e.get("xosUserPrefs")?JSON.parse(e.get("xosUserPrefs")):{}},this.setAll=function(n){e.put("xosUserPrefs",JSON.stringify(n))},this.getSynchronizerNotificationStatus=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0];return e?n.getAll().synchronizers.notification[e]:n.getAll().synchronizers.notification},this.setSynchronizerNotificationStatus=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0],o=arguments[1];if(!e)throw new Error("[XosUserPrefs] When updating a synchronizer is mandatory to provide a name.");var t=n.getAll();t.synchronizers||(t.synchronizers={notification:{}}),t.synchronizers.notification[e]=o,n.setAll(t)}}])}(),function(){angular.module("xos.helpers").service("GraphService",["$q","Tenants","Services",function(e,n,o){var t=this;this.loadCoarseData=function(){var t=void 0,i=e.defer();return o.query().$promise.then(function(e){return t=e,n.query({kind:"coarse"}).$promise}).then(function(e){i.resolve({tenants:e,services:t})}),i.promise},this.getCoarseGraph=function(){return t.loadCoarseData().then(function(e){console.log(e)}),"ciao"}}])}(),function(){angular.module("xos.helpers").factory("Notification",function(){return window.Notification}).service("xosNotification",["$q","$log","Notification",function(e,n,o){var t=this;this.checkPermission=function(){var n=e.defer();return o.requestPermission().then(function(e){"granted"===e?n.resolve(e):n.reject(e)}),n.promise},this.sendNotification=function(e,t){var i=new o(e,t);i.onerror=function(e){n.error(e)}},this.notify=function(e,i){"Notification"in window?"granted"!==o.permission?t.checkPermission().then(function(){return t.sendNotification(e,i)}):"granted"===o.permission&&t.sendNotification(e,i):n.info("This browser does not support desktop notification")}}])}(),function(){function e(){return{request:function(e){return-1===e.url.indexOf(".html")&&(e.url+="?no_hyperlinks=1"),e}}}angular.module("xos.helpers").factory("NoHyperlinks",e)}(),angular.module("xos.helpers").config(["$provide",function(e){e.decorator("$log",["$delegate",function(e){var n=function(){return window.location.href.indexOf("debug=true")>=0},o=e.log,t=e.info,i=e.warn,r=e.error,s=e.debug,a=function(o){return function(){if(n()){var t=[].slice.call(arguments),i=new Date;t[0]="["+i.getHours()+":"+i.getMinutes()+":"+i.getSeconds()+"] "+t[0],"function"!=typeof e.reset||e.debug.logs instanceof Array||e.reset(),o.apply(null,t)}}};return e.info=a(t),e.log=a(o),e.warn=a(i),e.error=a(r),e.debug=a(s),e}])}]),function(){function e(){var e=function(e){return e.split("_").join(" ").trim()},n=function(e){return e.split(/(?=[A-Z])/).map(function(e){return e.toLowerCase()}).join(" ")},o=function(e){return e.slice(0,1).toUpperCase()+e.slice(1)},t=function(t){return t=e(t),t=n(t),t=o(t).replace(/\s\s+/g," ")+":",t.replace("::",":")};return{_formatByUnderscore:e,_formatByUppercase:n,_capitalize:o,format:t}}angular.module("xos.uiComponents").factory("LabelFormatter",e)}(),function(){function e(e){return{request:function(n){return"GET"!==n.method&&(n.headers["X-CSRFToken"]=e.get("xoscsrftoken")),n}}}e.$inject=["$cookies"],angular.module("xos.helpers").factory("SetCSRFToken",e)}();
\ No newline at end of file
+"use strict";!function(){angular.module("xos.uiComponents",["chart.js","RecursionHelper"])}(),function(){angular.module("xos.uiComponents").directive("xosTable",function(){return{restrict:"E",scope:{data:"=",config:"="},template:'\n <div ng-show="vm.data.length > 0 && vm.loader == false">\n <div class="row" ng-if="vm.config.filter == \'fulltext\'">\n <div class="col-xs-12">\n <input\n class="form-control"\n placeholder="Type to search.."\n type="text"\n ng-model="vm.query"/>\n </div>\n </div>\n <table ng-class="vm.classes" ng-hide="vm.data.length == 0">\n <thead>\n <tr>\n <th ng-repeat="col in vm.columns">\n {{col.label}}\n <span ng-if="vm.config.order">\n <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = false">\n <i class="glyphicon glyphicon-chevron-up"></i>\n </a>\n <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = true">\n <i class="glyphicon glyphicon-chevron-down"></i>\n </a>\n </span>\n </th>\n <th ng-if="vm.config.actions">Actions:</th>\n </tr>\n </thead>\n <tbody ng-if="vm.config.filter == \'field\'">\n <tr>\n <td ng-repeat="col in vm.columns">\n <input\n ng-if="col.type !== \'boolean\'"\n class="form-control"\n placeholder="Type to search by {{col.label}}"\n type="text"\n ng-model="vm.query[col.prop]"/>\n <select\n ng-if="col.type === \'boolean\'"\n class="form-control"\n ng-model="vm.query[col.prop]">\n <option value="">-</option>\n <option value="true">True</option>\n <option value="false">False</option>\n </select>\n </td>\n <td ng-if="vm.config.actions"></td>\n </tr>\n </tbody>\n <tbody>\n <tr ng-repeat="item in vm.data | filter:vm.query:vm.comparator | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">\n <td ng-repeat="col in vm.columns" link-wrapper>\n <span ng-if="!col.type">{{item[col.prop]}}</span>\n <span ng-if="col.type === \'boolean\'">\n <i class="glyphicon"\n ng-class="{\'glyphicon-ok\': item[col.prop], \'glyphicon-remove\': !item[col.prop]}">\n </i>\n </span>\n <span ng-if="col.type === \'date\'">\n {{item[col.prop] | date:\'H:mm MMM d, yyyy\'}}\n </span>\n <span ng-if="col.type === \'array\'">\n {{item[col.prop] | arrayToList}}\n </span>\n <span ng-if="col.type === \'object\'">\n <dl class="dl-horizontal">\n <span ng-repeat="(k,v) in item[col.prop]">\n <dt>{{k}}</dt>\n <dd>{{v}}</dd>\n </span>\n </dl>\n </span>\n <span ng-if="col.type === \'custom\'">\n {{col.formatter(item)}}\n </span>\n <span ng-if="col.type === \'icon\'">\n <i class="glyphicon glyphicon-{{col.formatter(item)}}">\n </i>\n </span>\n </td>\n <td ng-if="vm.config.actions">\n <a href=""\n ng-repeat="action in vm.config.actions"\n ng-click="action.cb(item)"\n title="{{action.label}}">\n <i\n class="glyphicon glyphicon-{{action.icon}}"\n style="color: {{action.color}};"></i>\n </a>\n </td>\n </tr>\n </tbody>\n </table>\n <xos-pagination\n ng-if="vm.config.pagination"\n page-size="vm.config.pagination.pageSize"\n total-elements="vm.data.length"\n change="vm.goToPage">\n </xos-pagination>\n </div>\n <div ng-show="(vm.data.length == 0 || !vm.data) && vm.loader == false">\n <xos-alert config="{type: \'info\'}">\n No data to show.\n </xos-alert>\n </div>\n <div ng-show="vm.loader == true">\n <div class="loader"></div>\n </div>\n ',bindToController:!0,controllerAs:"vm",controller:["_","$scope","Comparator",function(e,n,o){var t=this;if(this.comparator=o,this.loader=!0,n.$watch(function(){return t.data},function(e){angular.isDefined(e)&&(t.loader=!1)}),!this.config)throw new Error('[xosTable] Please provide a configuration via the "config" attribute');if(!this.config.columns)throw new Error("[xosTable] Please provide a columns list in the configuration");this.config.order&&angular.isObject(this.config.order)&&(this.reverse=this.config.order.reverse||!1,this.orderBy=this.config.order.field||"id");var i=e.filter(this.config.columns,{type:"custom"});angular.isArray(i)&&i.length>0&&e.forEach(i,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided a custom field type, a formatter function should provided too.")});var r=e.filter(this.config.columns,{type:"icon"});angular.isArray(r)&&r.length>0&&e.forEach(r,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided an icon field type, a formatter function should provided too.")});var a=e.filter(this.config.columns,function(e){return angular.isDefined(e.link)});angular.isArray(a)&&a.length>0&&e.forEach(a,function(e){if(!angular.isFunction(e.link))throw new Error("[xosTable] The link property should be a function.")}),this.columns=this.config.columns,this.classes=this.config.classes||"table table-striped table-bordered",this.config.actions,this.config.pagination&&(this.currentPage=0,this.goToPage=function(e){t.currentPage=e})}]}}).filter("arrayToList",function(){return function(e){return angular.isArray(e)?e.join(", "):e}}).directive("linkWrapper",function(){return{restrict:"A",transclude:!0,template:'\n <a ng-if="col.link" href="{{col.link(item)}}">\n <div ng-transclude></div>\n </a>\n <div ng-transclude ng-if="!col.link"></div>\n '}})}(),function(){angular.module("xos.uiComponents").directive("xosValidation",function(){return{restrict:"E",scope:{field:"=",form:"="},template:'\n <div ng-cloak>\n <xos-alert config="vm.config" show="vm.field.$error.required !== undefined && vm.field.$error.required !== false && (vm.field.$touched || vm.form.$submitted)">\n Field required\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.email !== undefined && vm.field.$error.email !== false && (vm.field.$touched || vm.form.$submitted)">\n This is not a valid email\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.minlength !== undefined && vm.field.$error.minlength !== false && (vm.field.$touched || vm.form.$submitted)">\n Too short\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.maxlength !== undefined && vm.field.$error.maxlength !== false && (vm.field.$touched || vm.form.$submitted)">\n Too long\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.custom !== undefined && vm.field.$error.custom !== false && (vm.field.$touched || vm.form.$submitted)">\n Field invalid\n </xos-alert>\n </div>\n ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:function(){this.config={type:"danger"}}}})}(),function(){angular.module("xos.uiComponents").directive("xosPagination",function(){return{restrict:"E",scope:{pageSize:"=",totalElements:"=",change:"="},template:'\n <div class="row" ng-if="vm.pageList.length > 1">\n <div class="col-xs-12 text-center">\n <ul class="pagination">\n <li\n ng-click="vm.goToPage(vm.currentPage - 1)"\n ng-class="{disabled: vm.currentPage == 0}">\n <a href="" aria-label="Previous">\n <span aria-hidden="true">«</span>\n </a>\n </li>\n <li ng-repeat="i in vm.pageList" ng-class="{active: i === vm.currentPage}">\n <a href="" ng-click="vm.goToPage(i)">{{i + 1}}</a>\n </li>\n <li\n ng-click="vm.goToPage(vm.currentPage + 1)"\n ng-class="{disabled: vm.currentPage == vm.pages - 1}">\n <a href="" aria-label="Next">\n <span aria-hidden="true">»</span>\n </a>\n </li>\n </ul>\n </div>\n </div>\n ',bindToController:!0,controllerAs:"vm",controller:["$scope",function(e){var n=this;this.currentPage=0,this.goToPage=function(e){0>e||e===n.pages||(n.currentPage=e,n.change(e))},this.createPages=function(e){for(var n=[],o=0;e>o;o++)n.push(o);return n},e.$watch(function(){return n.totalElements},function(){n.totalElements&&(n.pages=Math.ceil(n.totalElements/n.pageSize),n.pageList=n.createPages(n.pages))})}]}}).filter("pagination",function(){return function(e,n){return e&&angular.isArray(e)?(n=parseInt(n,10),e.slice(n)):e}})}(),function(){angular.module("xos.uiComponents").directive("xosField",["RecursionHelper",function(e){return{restrict:"E",scope:{name:"=",field:"=",ngModel:"="},template:'\n <label ng-if="vm.field.type !== \'object\'">{{vm.field.label}}</label>\n <input\n ng-if="vm.field.type !== \'boolean\' && vm.field.type !== \'object\' && vm.field.type !== \'select\'"\n type="{{vm.field.type}}"\n name="{{vm.name}}"\n class="form-control"\n ng-model="vm.ngModel"\n ng-minlength="vm.field.validators.minlength || 0"\n ng-maxlength="vm.field.validators.maxlength || 2000"\n ng-required="vm.field.validators.required || false" />\n <select class="form-control" ng-if ="vm.field.type === \'select\'"\n name = "{{vm.name}}"\n ng-options="item.id as item.label for item in vm.field.options track by item.id"\n ng-model="vm.ngModel"\n ng-required="vm.field.validators.required || false">\n </select>\n <span class="boolean-field" ng-if="vm.field.type === \'boolean\'">\n <button\n class="btn btn-success"\n ng-show="vm.ngModel"\n ng-click="vm.ngModel = false">\n <i class="glyphicon glyphicon-ok"></i>\n </button>\n <button\n class="btn btn-danger"\n ng-show="!vm.ngModel"\n ng-click="vm.ngModel = true">\n <i class="glyphicon glyphicon-remove"></i>\n </button>\n </span>\n <div\n class="panel panel-default object-field"\n ng-if="vm.field.type == \'object\' && (!vm.isEmptyObject(vm.ngModel) || !vm.isEmptyObject(vm.field.properties))"\n >\n <div class="panel-heading">{{vm.field.label}}</div>\n <div class="panel-body">\n <div ng-if="!vm.field.properties" ng-repeat="(k, v) in vm.ngModel">\n <xos-field\n name="k"\n field="{label: vm.formatLabel(k), type: vm.getType(v)}"\n ng-model="v">\n </xos-field>\n </div>\n <div ng-if="vm.field.properties" ng-repeat="(k, v) in vm.field.properties">\n <xos-field\n name="k"\n field="{\n label: v.label || vm.formatLabel(k),\n type: v.type,\n validators: v.validators\n }"\n ng-model="vm.ngModel[k]">\n </xos-field>\n </div>\n </div>\n </div>\n ',bindToController:!0,controllerAs:"vm",compile:function(n){return e.compile(n)},controller:["$attrs","XosFormHelpers","LabelFormatter",function(e,n,o){if(!this.name)throw new Error("[xosField] Please provide a field name");if(!this.field)throw new Error("[xosField] Please provide a field definition");if(!this.field.type)throw new Error("[xosField] Please provide a type in the field definition");if(!e.ngModel)throw new Error("[xosField] Please provide an ng-model");this.getType=n._getFieldFormat,this.formatLabel=o.format,this.isEmptyObject=function(e){return e?0===Object.keys(e).length:!0}}]}}])}(),function(){angular.module("xos.uiComponents").directive("xosForm",function(){return{restrict:"E",scope:{config:"=",ngModel:"="},template:'\n <ng-form name="vm.{{vm.config.formName || \'form\'}}">\n <div class="form-group" ng-repeat="(name, field) in vm.formField">\n <xos-field name="name" field="field" ng-model="vm.ngModel[name]"></xos-field>\n <xos-validation field="vm[vm.config.formName || \'form\'][name]" form="vm[vm.config.formName || \'form\']"></xos-validation>\n </div>\n <div class="form-group" ng-if="vm.config.actions">\n <button role="button" href=""\n ng-repeat="action in vm.config.actions"\n ng-click="action.cb(vm.ngModel)"\n class="btn btn-{{action.class}}"\n title="{{action.label}}">\n <i class="glyphicon glyphicon-{{action.icon}}"></i>\n {{action.label}}\n </button>\n </div>\n </ng-form>\n ',bindToController:!0,controllerAs:"vm",controller:["$scope","$log","_","XosFormHelpers",function(e,n,o,t){var i=this;if(!this.config)throw new Error('[xosForm] Please provide a configuration via the "config" attribute');if(!this.config.actions)throw new Error("[xosForm] Please provide an action list in the configuration");this.excludedField=["id","validators","created","updated","deleted","backend_status"],this.config&&this.config.exclude&&(this.excludedField=this.excludedField.concat(this.config.exclude)),this.formField=[],e.$watch(function(){return i.ngModel},function(e){if(i.formField={},e){var n=o.difference(Object.keys(e),i.excludedField),r=t.parseModelField(n);i.formField=t.buildFormStructure(r,i.config.fields,e)}})}]}})}(),function(){angular.module("xos.uiComponents").directive("xosAlert",function(){return{restrict:"E",scope:{config:"=",show:"=?"},template:'\n <div ng-cloak class="alert alert-{{vm.config.type}}" ng-hide="!vm.show">\n <button type="button" class="close" ng-if="vm.config.closeBtn" ng-click="vm.dismiss()">\n <span aria-hidden="true">×</span>\n </button>\n <p ng-transclude></p>\n </div>\n ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:["$timeout",function(e){var n=this;if(!this.config)throw new Error('[xosAlert] Please provide a configuration via the "config" attribute');this.show=this.show!==!1,this.dismiss=function(){n.show=!1},this.config.autoHide&&!function(){var o=e(function(){n.dismiss(),e.cancel(o)},n.config.autoHide)}()}]}})}(),function(){angular.module("xos.uiComponents").directive("xosSmartPie",function(){return{restrict:"E",scope:{config:"="},template:'\n <canvas\n class="chart chart-pie {{vm.config.classes}}"\n chart-data="vm.data" chart-labels="vm.labels"\n chart-legend="{{vm.config.legend}}">\n </canvas>\n ',bindToController:!0,controllerAs:"vm",controller:["$injector","$interval","$scope","$timeout","_",function(e,n,o,t,i){var r=this;if(!this.config.resource&&!this.config.data)throw new Error("[xosSmartPie] Please provide a resource or an array of data in the configuration");var a=function(e){return i.groupBy(e,r.config.groupBy)},s=function(e){return i.reduce(Object.keys(e),function(n,o){return n.concat(e[o].length)},[])},l=function(e){return angular.isFunction(r.config.labelFormatter)?r.config.labelFormatter(Object.keys(e)):Object.keys(e)},c=function(e){var n=a(e);r.data=s(n),r.labels=l(n)};this.config.resource?!function(){r.Resource=e.get(r.config.resource);var o=function(){r.Resource.query().$promise.then(function(e){e[0]&&c(e)})};o(),r.config.poll&&n(function(){o()},1e3*r.config.poll)}():o.$watch(function(){return r.config.data},function(e){e&&c(r.config.data)},!0),o.$on("create",function(e,n){console.log("create: "+n.id)}),o.$on("destroy",function(e,n){console.log("destroy: "+n.id)})}]}})}();var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(){angular.module("xos.uiComponents").directive("xosSmartTable",function(){return{restrict:"E",scope:{config:"="},template:'\n <div class="row" ng-show="vm.data.length > 0">\n <div class="col-xs-12 text-right">\n <a href="" class="btn btn-success" ng-click="vm.createItem()">\n Add\n </a>\n </div>\n </div>\n <div class="row">\n <div class="col-xs-12 table-responsive">\n <xos-table config="vm.tableConfig" data="vm.data"></xos-table>\n </div>\n </div>\n <div class="panel panel-default" ng-show="vm.detailedItem">\n <div class="panel-heading">\n <div class="row">\n <div class="col-xs-11">\n <h3 class="panel-title" ng-show="vm.detailedItem.id">Update {{vm.config.resource}} {{vm.detailedItem.id}}</h3>\n <h3 class="panel-title" ng-show="!vm.detailedItem.id">Create {{vm.config.resource}} item</h3>\n </div>\n <div class="col-xs-1">\n <a href="" ng-click="vm.cleanForm()">\n <i class="glyphicon glyphicon-remove pull-right"></i>\n </a>\n </div>\n </div>\n </div>\n <div class="panel-body">\n <xos-form config="vm.formConfig" ng-model="vm.detailedItem"></xos-form>\n </div>\n </div>\n <xos-alert config="{type: \'success\', closeBtn: true}" show="vm.responseMsg">{{vm.responseMsg}}</xos-alert>\n <xos-alert config="{type: \'danger\', closeBtn: true}" show="vm.responseErr">{{vm.responseErr}}</xos-alert>\n ',bindToController:!0,controllerAs:"vm",controller:["$injector","LabelFormatter","_","XosFormHelpers",function(e,n,o,t){var i=this;this.responseMsg=!1,this.responseErr=!1,this.tableConfig={columns:[],actions:[{label:"delete",icon:"remove",cb:function(e){i.Resource["delete"]({id:e.id}).$promise.then(function(){o.remove(i.data,function(n){return n.id===e.id}),i.responseMsg=i.config.resource+" with id "+e.id+" successfully deleted"})["catch"](function(n){i.responseErr=n.data.detail||"Error while deleting "+i.config.resource+" with id "+e.id})},color:"red"},{label:"details",icon:"search",cb:function(e){i.detailedItem=e}}],classes:"table table-striped table-bordered table-responsive",filter:"field",order:!0,pagination:{pageSize:10}},this.formConfig={exclude:this.config.hiddenFields,fields:{},formName:this.config.resource+"Form",actions:[{label:"Save",icon:"ok",cb:function(e){var n=void 0,o=!0;e.id?(n=e.$update(),o=!1):n=e.$save(),n.then(function(n){o&&i.data.push(angular.copy(n)),delete i.detailedItem,i.responseMsg=i.config.resource+" with id "+e.id+" successfully saved"})["catch"](function(n){i.responseErr=n.data.detail||"Error while saving "+i.config.resource+" with id "+e.id})},"class":"success"}]},this.cleanForm=function(){delete i.detailedItem},this.createItem=function(){i.detailedItem=new i.Resource},this.Resource=e.get(this.config.resource);var r=function(){i.Resource.query().$promise.then(function(e){if(!e[0])return void(i.data=e);var r=e[0],a=Object.keys(r);o.remove(a,function(e){return"id"===e||"validators"===e}),angular.isArray(i.config.hiddenFields)&&(a=o.difference(a,i.config.hiddenFields));var s=a.map(function(e){return n.format(e)});a.forEach(function(e,n){var o={label:s[n],prop:e};"string"!=typeof r[e]&&"undefined"!=typeof r[e]&&(o.type=_typeof(r[e])),i.tableConfig.columns.push(o)}),a.forEach(function(e,o){i.formConfig.fields[e]={label:n.format(s[o]).replace(":",""),type:t._getFieldFormat(r[e])}}),i.data=e})};r()}]}})}(),function(){function e(){var e=function(e){return e.split("_").join(" ").trim()},n=function(e){return e.split(/(?=[A-Z])/).map(function(e){return e.toLowerCase()}).join(" ")},o=function(e){return e.slice(0,1).toUpperCase()+e.slice(1)},t=function(t){return t=e(t),t=n(t),t=o(t).replace(/\s\s+/g," ")+":",t.replace("::",":")};return{_formatByUnderscore:e,_formatByUppercase:n,_capitalize:o,format:t}}angular.module("xos.uiComponents").factory("LabelFormatter",e)}();var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(){angular.module("xos.uiComponents").service("XosFormHelpers",["_","LabelFormatter",function(e,n){var o=this;this._isEmail=function(e){var n=/(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;return n.test(e)},this._getFieldFormat=function(n){return angular.isArray(n)?"array":e.isDate(n)||!Number.isNaN(Date.parse(n))&&new Date(n).getTime()>6311808e5?"date":"boolean"==typeof n?"boolean":o._isEmail(n)?"email":"string"==typeof n||null===n?"text":"undefined"==typeof n?"undefined":_typeof(n)},this.buildFormStructure=function(t,i,r){return t=angular.extend(t,i),i=i||{},e.reduce(Object.keys(t),function(e,t){return e[t]={label:i[t]&&i[t].label?i[t].label+":":n.format(t),type:i[t]&&i[t].type?i[t].type:o._getFieldFormat(r[t]),validators:i[t]&&i[t].validators?i[t].validators:{},hint:i[t]&&i[t].hint?i[t].hint:""},i[t]&&i[t].options&&(e[t].options=i[t].options),i[t]&&i[t].properties&&(e[t].properties=i[t].properties),"date"===e[t].type&&(r[t]=new Date(r[t])),"number"===e[t].type&&(r[t]=parseInt(r[t],10)),e},{})},this.parseModelField=function(n){return e.reduce(n,function(e,n){return e[n]={},e},{})}}])}(),function(){function e(){return function(e,n){if(angular.isUndefined(e))return!1;if(null===e||null===n)return e===n;if(angular.isObject(n)||angular.isObject(e))return angular.equals(n,e);if(_.isBoolean(e)||_.isBoolean(n))return 0!==e&&1!==e||(e=!!e),angular.equals(n,e);if(!angular.isString(e)||!angular.isString(n)){if(!angular.isDefined(e.toString)||!angular.isDefined(n.toString))return e===n;e=e.toString(),n=n.toString()}return e=e.toLowerCase()+"",n=n.toLowerCase()+"",-1!==e.indexOf(n)}}angular.module("xos.uiComponents").factory("Comparator",e)}(),function(){function e(e,n,o){e.interceptors.push("SetCSRFToken"),n.startSymbol("{$"),n.endSymbol("$}"),o.defaults.stripTrailingSlashes=!1}e.$inject=["$httpProvider","$interpolateProvider","$resourceProvider"],angular.module("bugSnag",[]).factory("$exceptionHandler",function(){return function(e,n){window.Bugsnag?Bugsnag.notifyException(e,{diagnostics:{cause:n}}):console.error(e,n,e.stack)}}),angular.module("xos.helpers",["ngCookies","ngResource","ngAnimate","bugSnag","xos.uiComponents"]).config(e).factory("_",["$window",function(e){return e._}])}(),function(){angular.module("xos.helpers").service("vSG-Collection",["$resource",function(e){return e("/api/service/vsg/")}])}(),function(){angular.module("xos.helpers").service("vOLT-Collection",["$resource",function(e){return e("/api/tenant/cord/volt/:volt_id/",{volt_id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Login",["$resource",function(e){return e("/api/utility/login/")}]).service("Logout",["$resource",function(e){return e("/api/utility/logout/")}])}(),function(){angular.module("xos.helpers").service("Users",["$resource",function(e){return e("/api/core/users/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Truckroll",["$resource",function(e){return e("/api/tenant/truckroll/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Tenants",["$resource",function(e){return e("/api/core/tenants/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Subscribers",["$resource",function(e){return e("/api/tenant/cord/subscriber/:id/",{id:"@id"},{update:{method:"PUT"},"View-a-Subscriber-Features-Detail":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/"},"Read-Subscriber-uplink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Update-Subscriber-uplink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Read-Subscriber-downlink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Update-Subscriber-downlink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Read-Subscriber-cdn":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Update-Subscriber-cdn":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Read-Subscriber-uverse":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Update-Subscriber-uverse":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Read-Subscriber-status":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"},"Update-Subscriber-status":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"}})}])}(),function(){angular.module("xos.helpers").service("SlicesPlus",["$http","$q",function(e,n){this.query=function(o){var t=n.defer();return e.get("/api/utility/slicesplus/",{params:o}).then(function(e){t.resolve(e.data)})["catch"](function(e){t.reject(e.data)}),{$promise:t.promise}},this.get=function(o,t){var i=n.defer();return e.get("/api/utility/slicesplus/"+o,{params:t}).then(function(e){i.resolve(e.data)})["catch"](function(e){i.reject(e.data)}),{$promise:i.promise}}}])}(),function(){angular.module("xos.helpers").service("Slices",["$resource",function(e){return e("/api/core/slices/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Sites",["$resource",function(e){return e("/api/core/sites/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Services",["$resource",function(e){return e("/api/core/services/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("ONOS-Services-Collection",["$resource",function(e){return e("/api/service/onos/")}])}(),function(){angular.module("xos.helpers").service("ONOS-App-Collection",["$resource",function(e){return e("/api/tenant/onos/app/")}])}(),function(){angular.module("xos.helpers").service("Nodes",["$resource",function(e){return e("/api/core/nodes/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Networks",["$resource",function(e){return e("/api/core/networks/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Instances",["$resource",function(e){return e("/api/core/instances/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Flavors",["$resource",function(e){return e("/api/core/flavors/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Example-Services-Collection",["$resource",function(e){return e("/api/service/exampleservice/")}])}(),function(){angular.module("xos.helpers").service("Deployments",["$resource",function(e){return e("/api/core/deployments/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("XosUserPrefs",["$cookies",function(e){var n=this,o=e.get("xosUserPrefs")?JSON.parse(e.get("xosUserPrefs")):{};this.getAll=function(){return o=e.get("xosUserPrefs")?JSON.parse(e.get("xosUserPrefs")):{}},this.setAll=function(n){e.put("xosUserPrefs",JSON.stringify(n))},this.getSynchronizerNotificationStatus=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0];return e?n.getAll().synchronizers.notification[e]:n.getAll().synchronizers.notification},this.setSynchronizerNotificationStatus=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0],o=arguments[1];if(!e)throw new Error("[XosUserPrefs] When updating a synchronizer is mandatory to provide a name.");var t=n.getAll();t.synchronizers||(t.synchronizers={notification:{}}),t.synchronizers.notification[e]=o,n.setAll(t)}}])}(),function(){angular.module("xos.helpers").service("GraphService",["$q","Tenants","Services",function(e,n,o){var t=this;this.loadCoarseData=function(){var t=void 0,i=e.defer();return o.query().$promise.then(function(e){return t=e,n.query({kind:"coarse"}).$promise}).then(function(e){i.resolve({tenants:e,services:t})}),i.promise},this.getCoarseGraph=function(){return t.loadCoarseData().then(function(e){console.log(e)}),"ciao"}}])}(),function(){angular.module("xos.helpers").factory("Notification",function(){return window.Notification}).service("xosNotification",["$q","$log","Notification",function(e,n,o){var t=this;this.checkPermission=function(){var n=e.defer();return o.requestPermission().then(function(e){"granted"===e?n.resolve(e):n.reject(e)}),n.promise},this.sendNotification=function(e,t){var i=new o(e,t);i.onerror=function(e){n.error(e)}},this.notify=function(e,i){"Notification"in window?"granted"!==o.permission?t.checkPermission().then(function(){return t.sendNotification(e,i)}):"granted"===o.permission&&t.sendNotification(e,i):n.info("This browser does not support desktop notification")}}])}(),function(){function e(){return{request:function(e){return-1===e.url.indexOf(".html")&&(e.url+="?no_hyperlinks=1"),e}}}angular.module("xos.helpers").factory("NoHyperlinks",e)}(),angular.module("xos.helpers").config(["$provide",function(e){e.decorator("$log",["$delegate",function(e){var n=function(){return window.location.href.indexOf("debug=true")>=0},o=e.log,t=e.info,i=e.warn,r=e.error,a=e.debug,s=function(o){return function(){if(n()){var t=[].slice.call(arguments),i=new Date;t[0]="["+i.getHours()+":"+i.getMinutes()+":"+i.getSeconds()+"] "+t[0],"function"!=typeof e.reset||e.debug.logs instanceof Array||e.reset(),o.apply(null,t)}}};return e.info=s(t),e.log=s(o),e.warn=s(i),e.error=s(r),e.debug=s(a),e}])}]),function(){function e(){var e=function(e){return e.split("_").join(" ").trim()},n=function(e){return e.split(/(?=[A-Z])/).map(function(e){return e.toLowerCase()}).join(" ")},o=function(e){return e.slice(0,1).toUpperCase()+e.slice(1)},t=function(t){return t=e(t),t=n(t),t=o(t).replace(/\s\s+/g," ")+":",t.replace("::",":")};return{_formatByUnderscore:e,_formatByUppercase:n,_capitalize:o,format:t}}angular.module("xos.uiComponents").factory("LabelFormatter",e);
+}(),function(){function e(e){return{request:function(n){return"GET"!==n.method&&(n.headers["X-CSRFToken"]=e.get("xoscsrftoken")),n}}}e.$inject=["$cookies"],angular.module("xos.helpers").factory("SetCSRFToken",e)}();
\ No newline at end of file
diff --git a/xos/services/ceilometer/admin.py b/xos/onboard/ceilometer/admin.py
similarity index 100%
rename from xos/services/ceilometer/admin.py
rename to xos/onboard/ceilometer/admin.py
diff --git a/xos/api/tenant/ceilometer/monitoringchannel.py b/xos/onboard/ceilometer/api/tenant/ceilometer/monitoringchannel.py
similarity index 100%
rename from xos/api/tenant/ceilometer/monitoringchannel.py
rename to xos/onboard/ceilometer/api/tenant/ceilometer/monitoringchannel.py
diff --git a/xos/onboard/ceilometer/ceilometer-onboard.yaml b/xos/onboard/ceilometer/ceilometer-onboard.yaml
new file mode 100644
index 0000000..82c955f
--- /dev/null
+++ b/xos/onboard/ceilometer/ceilometer-onboard.yaml
@@ -0,0 +1,25 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+ - custom_types/xos.yaml
+
+topology_template:
+ node_templates:
+ servicecontroller#ceilometer:
+ type: tosca.nodes.ServiceController
+ properties:
+ base_url: file:///opt/xos/onboard/ceilometer/
+ # The following will concatenate with base_url automatically, if
+ # base_url is non-null.
+ models: models.py
+ admin: admin.py
+ admin_template: templates/ceilometeradmin.html, templates/sflowadmin.html
+ synchronizer: synchronizer/manifest
+ synchronizer_run: monitoring_channel_synchronizer.py
+ tosca_resource: tosca/resources/ceilometerservice.py, tosca/resources/ceilometertenant.py, tosca/resources/sflowservice.py
+ rest_tenant: subdirectory:ceilometer api/tenant/ceilometer/monitoringchannel.py
+ private_key: file:///opt/xos/key_import/monitoring_channel_rsa
+ public_key: file:///opt/xos/key_import/monitoring_channel_rsa.pub
+
diff --git a/xos/services/ceilometer/models.py b/xos/onboard/ceilometer/models.py
similarity index 100%
rename from xos/services/ceilometer/models.py
rename to xos/onboard/ceilometer/models.py
diff --git a/xos/synchronizers/monitoring_channel/files/docker.list b/xos/onboard/ceilometer/synchronizer/files/docker.list
similarity index 100%
rename from xos/synchronizers/monitoring_channel/files/docker.list
rename to xos/onboard/ceilometer/synchronizer/files/docker.list
diff --git a/xos/synchronizers/monitoring_channel/files/vm-resolv.conf b/xos/onboard/ceilometer/synchronizer/files/vm-resolv.conf
similarity index 100%
rename from xos/synchronizers/monitoring_channel/files/vm-resolv.conf
rename to xos/onboard/ceilometer/synchronizer/files/vm-resolv.conf
diff --git a/xos/onboard/ceilometer/synchronizer/manifest b/xos/onboard/ceilometer/synchronizer/manifest
new file mode 100644
index 0000000..c679225
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/manifest
@@ -0,0 +1,26 @@
+templates/Dockerfile.monitoring_channel
+templates/ceilometer_proxy_config.j2
+templates/Dockerfile.sflowpubsub
+templates/sflow_pub_sub/sample_sflow_pub_sub.conf_sample
+templates/sflow_pub_sub/README
+templates/sflow_pub_sub/sflow_sub_records.py
+templates/sflow_pub_sub/start_sflow_pub_sub
+templates/sflow_pub_sub/sflow_pub_sub_main.py
+templates/sflow_pub_sub/sflow_pub_sub_config.j2
+templates/start-monitoring-channel.sh.j2
+templates/monitoring-channel.conf.j2
+templates/ceilometer_proxy_server.py
+templates/start_ceilometer_proxy
+manifest
+monitoring_channel_synchronizer_config
+steps/sync_sflowtenant.yaml
+steps/sync_sflowtenant.py
+steps/sync_monitoringchannel.yaml
+steps/sync_monitoringchannel.py
+steps/sync_sflowservice.yaml
+steps/sync_sflowservice.py
+files/vm-resolv.conf
+files/docker.list
+model-deps
+supervisor/monitoring_channel_observer.conf
+monitoring_channel_synchronizer.py
diff --git a/xos/synchronizers/vtr/model-deps b/xos/onboard/ceilometer/synchronizer/model-deps
similarity index 100%
rename from xos/synchronizers/vtr/model-deps
rename to xos/onboard/ceilometer/synchronizer/model-deps
diff --git a/xos/synchronizers/monitoring_channel/monitoring_channel_synchronizer.py b/xos/onboard/ceilometer/synchronizer/monitoring_channel_synchronizer.py
similarity index 100%
rename from xos/synchronizers/monitoring_channel/monitoring_channel_synchronizer.py
rename to xos/onboard/ceilometer/synchronizer/monitoring_channel_synchronizer.py
diff --git a/xos/synchronizers/monitoring_channel/monitoring_channel_synchronizer_config b/xos/onboard/ceilometer/synchronizer/monitoring_channel_synchronizer_config
similarity index 100%
rename from xos/synchronizers/monitoring_channel/monitoring_channel_synchronizer_config
rename to xos/onboard/ceilometer/synchronizer/monitoring_channel_synchronizer_config
diff --git a/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.py b/xos/onboard/ceilometer/synchronizer/steps/sync_monitoringchannel.py
similarity index 100%
rename from xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.py
rename to xos/onboard/ceilometer/synchronizer/steps/sync_monitoringchannel.py
diff --git a/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml b/xos/onboard/ceilometer/synchronizer/steps/sync_monitoringchannel.yaml
similarity index 100%
rename from xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml
rename to xos/onboard/ceilometer/synchronizer/steps/sync_monitoringchannel.yaml
diff --git a/xos/synchronizers/monitoring_channel/steps/sync_sflowservice.py b/xos/onboard/ceilometer/synchronizer/steps/sync_sflowservice.py
similarity index 100%
rename from xos/synchronizers/monitoring_channel/steps/sync_sflowservice.py
rename to xos/onboard/ceilometer/synchronizer/steps/sync_sflowservice.py
diff --git a/xos/synchronizers/monitoring_channel/steps/sync_sflowservice.yaml b/xos/onboard/ceilometer/synchronizer/steps/sync_sflowservice.yaml
similarity index 100%
rename from xos/synchronizers/monitoring_channel/steps/sync_sflowservice.yaml
rename to xos/onboard/ceilometer/synchronizer/steps/sync_sflowservice.yaml
diff --git a/xos/synchronizers/monitoring_channel/steps/sync_sflowtenant.py b/xos/onboard/ceilometer/synchronizer/steps/sync_sflowtenant.py
similarity index 100%
rename from xos/synchronizers/monitoring_channel/steps/sync_sflowtenant.py
rename to xos/onboard/ceilometer/synchronizer/steps/sync_sflowtenant.py
diff --git a/xos/synchronizers/monitoring_channel/steps/sync_sflowtenant.yaml b/xos/onboard/ceilometer/synchronizer/steps/sync_sflowtenant.yaml
similarity index 100%
rename from xos/synchronizers/monitoring_channel/steps/sync_sflowtenant.yaml
rename to xos/onboard/ceilometer/synchronizer/steps/sync_sflowtenant.yaml
diff --git a/xos/synchronizers/monitoring_channel/supervisor/monitoring_channel_observer.conf b/xos/onboard/ceilometer/synchronizer/supervisor/monitoring_channel_observer.conf
similarity index 100%
rename from xos/synchronizers/monitoring_channel/supervisor/monitoring_channel_observer.conf
rename to xos/onboard/ceilometer/synchronizer/supervisor/monitoring_channel_observer.conf
diff --git a/xos/synchronizers/monitoring_channel/templates/Dockerfile.monitoring_channel b/xos/onboard/ceilometer/synchronizer/templates/Dockerfile.monitoring_channel
similarity index 100%
rename from xos/synchronizers/monitoring_channel/templates/Dockerfile.monitoring_channel
rename to xos/onboard/ceilometer/synchronizer/templates/Dockerfile.monitoring_channel
diff --git a/xos/synchronizers/monitoring_channel/templates/Dockerfile.sflowpubsub b/xos/onboard/ceilometer/synchronizer/templates/Dockerfile.sflowpubsub
similarity index 100%
rename from xos/synchronizers/monitoring_channel/templates/Dockerfile.sflowpubsub
rename to xos/onboard/ceilometer/synchronizer/templates/Dockerfile.sflowpubsub
diff --git a/xos/synchronizers/monitoring_channel/templates/ceilometer_proxy_config.j2 b/xos/onboard/ceilometer/synchronizer/templates/ceilometer_proxy_config.j2
similarity index 100%
rename from xos/synchronizers/monitoring_channel/templates/ceilometer_proxy_config.j2
rename to xos/onboard/ceilometer/synchronizer/templates/ceilometer_proxy_config.j2
diff --git a/xos/synchronizers/monitoring_channel/templates/ceilometer_proxy_server.py b/xos/onboard/ceilometer/synchronizer/templates/ceilometer_proxy_server.py
similarity index 100%
rename from xos/synchronizers/monitoring_channel/templates/ceilometer_proxy_server.py
rename to xos/onboard/ceilometer/synchronizer/templates/ceilometer_proxy_server.py
diff --git a/xos/synchronizers/monitoring_channel/templates/monitoring-channel.conf.j2 b/xos/onboard/ceilometer/synchronizer/templates/monitoring-channel.conf.j2
similarity index 100%
rename from xos/synchronizers/monitoring_channel/templates/monitoring-channel.conf.j2
rename to xos/onboard/ceilometer/synchronizer/templates/monitoring-channel.conf.j2
diff --git a/xos/synchronizers/monitoring_channel/templates/sflow_pub_sub/README b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/README
similarity index 100%
rename from xos/synchronizers/monitoring_channel/templates/sflow_pub_sub/README
rename to xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/README
diff --git a/xos/synchronizers/monitoring_channel/templates/sflow_pub_sub/sample_sflow_pub_sub.conf_sample b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sample_sflow_pub_sub.conf_sample
similarity index 100%
rename from xos/synchronizers/monitoring_channel/templates/sflow_pub_sub/sample_sflow_pub_sub.conf_sample
rename to xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sample_sflow_pub_sub.conf_sample
diff --git a/xos/synchronizers/monitoring_channel/templates/sflow_pub_sub/sflow_pub_sub_config.j2 b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sflow_pub_sub_config.j2
similarity index 100%
rename from xos/synchronizers/monitoring_channel/templates/sflow_pub_sub/sflow_pub_sub_config.j2
rename to xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sflow_pub_sub_config.j2
diff --git a/xos/synchronizers/monitoring_channel/templates/sflow_pub_sub/sflow_pub_sub_main.py b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sflow_pub_sub_main.py
similarity index 100%
rename from xos/synchronizers/monitoring_channel/templates/sflow_pub_sub/sflow_pub_sub_main.py
rename to xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sflow_pub_sub_main.py
diff --git a/xos/synchronizers/monitoring_channel/templates/sflow_pub_sub/sflow_sub_records.py b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sflow_sub_records.py
similarity index 100%
rename from xos/synchronizers/monitoring_channel/templates/sflow_pub_sub/sflow_sub_records.py
rename to xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sflow_sub_records.py
diff --git a/xos/synchronizers/monitoring_channel/templates/sflow_pub_sub/start_sflow_pub_sub b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/start_sflow_pub_sub
similarity index 100%
rename from xos/synchronizers/monitoring_channel/templates/sflow_pub_sub/start_sflow_pub_sub
rename to xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/start_sflow_pub_sub
diff --git a/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2 b/xos/onboard/ceilometer/synchronizer/templates/start-monitoring-channel.sh.j2
similarity index 100%
rename from xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2
rename to xos/onboard/ceilometer/synchronizer/templates/start-monitoring-channel.sh.j2
diff --git a/xos/synchronizers/monitoring_channel/templates/start_ceilometer_proxy b/xos/onboard/ceilometer/synchronizer/templates/start_ceilometer_proxy
similarity index 100%
rename from xos/synchronizers/monitoring_channel/templates/start_ceilometer_proxy
rename to xos/onboard/ceilometer/synchronizer/templates/start_ceilometer_proxy
diff --git a/xos/services/ceilometer/templates/ceilometeradmin.html b/xos/onboard/ceilometer/templates/ceilometeradmin.html
similarity index 100%
rename from xos/services/ceilometer/templates/ceilometeradmin.html
rename to xos/onboard/ceilometer/templates/ceilometeradmin.html
diff --git a/xos/services/ceilometer/templates/sflowadmin.html b/xos/onboard/ceilometer/templates/sflowadmin.html
similarity index 100%
rename from xos/services/ceilometer/templates/sflowadmin.html
rename to xos/onboard/ceilometer/templates/sflowadmin.html
diff --git a/xos/tosca/resources/ceilometerservice.py b/xos/onboard/ceilometer/tosca/resources/ceilometerservice.py
similarity index 100%
rename from xos/tosca/resources/ceilometerservice.py
rename to xos/onboard/ceilometer/tosca/resources/ceilometerservice.py
diff --git a/xos/tosca/resources/ceilometertenant.py b/xos/onboard/ceilometer/tosca/resources/ceilometertenant.py
similarity index 100%
rename from xos/tosca/resources/ceilometertenant.py
rename to xos/onboard/ceilometer/tosca/resources/ceilometertenant.py
diff --git a/xos/tosca/resources/sflowservice.py b/xos/onboard/ceilometer/tosca/resources/sflowservice.py
similarity index 100%
rename from xos/tosca/resources/sflowservice.py
rename to xos/onboard/ceilometer/tosca/resources/sflowservice.py
diff --git a/xos/onboard/exampleservice/api/tenant/exampletenant.py b/xos/onboard/exampleservice/api/tenant/exampletenant.py
index c50680f..f4778cc 100644
--- a/xos/onboard/exampleservice/api/tenant/exampletenant.py
+++ b/xos/onboard/exampleservice/api/tenant/exampletenant.py
@@ -6,7 +6,6 @@
from rest_framework import status
from core.models import *
from django.forms import widgets
-from services.cord.models import CordSubscriberRoot
from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
diff --git a/xos/services/fabric/admin.py b/xos/onboard/fabric/admin.py
similarity index 100%
rename from xos/services/fabric/admin.py
rename to xos/onboard/fabric/admin.py
diff --git a/xos/onboard/fabric/fabric-onboard.yaml b/xos/onboard/fabric/fabric-onboard.yaml
new file mode 100644
index 0000000..e0f0fa7
--- /dev/null
+++ b/xos/onboard/fabric/fabric-onboard.yaml
@@ -0,0 +1,24 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the fabric
+
+imports:
+ - custom_types/xos.yaml
+
+topology_template:
+ node_templates:
+ servicecontroller#fabric:
+ type: tosca.nodes.ServiceController
+ properties:
+ base_url: file:///opt/xos/onboard/fabric/
+ # The following will concatenate with base_url automatically, if
+ # base_url is non-null.
+ models: models.py
+ admin: admin.py
+ admin_template: templates/fabricadmin.html
+ synchronizer: synchronizer/manifest
+ synchronizer_run: fabric-synchronizer.py
+ tosca_resource: tosca/resources/fabricservice.py
+ #private_key: file:///opt/xos/key_import/vsg_rsa
+ #public_key: file:///opt/xos/key_import/vsg_rsa.pub
+
diff --git a/xos/services/fabric/models.py b/xos/onboard/fabric/models.py
similarity index 100%
rename from xos/services/fabric/models.py
rename to xos/onboard/fabric/models.py
diff --git a/xos/synchronizers/fabric/fabric-synchronizer.py b/xos/onboard/fabric/synchronizer/fabric-synchronizer.py
similarity index 100%
rename from xos/synchronizers/fabric/fabric-synchronizer.py
rename to xos/onboard/fabric/synchronizer/fabric-synchronizer.py
diff --git a/xos/synchronizers/fabric/fabric_synchronizer_config b/xos/onboard/fabric/synchronizer/fabric_synchronizer_config
similarity index 100%
rename from xos/synchronizers/fabric/fabric_synchronizer_config
rename to xos/onboard/fabric/synchronizer/fabric_synchronizer_config
diff --git a/xos/onboard/fabric/synchronizer/manifest b/xos/onboard/fabric/synchronizer/manifest
new file mode 100644
index 0000000..62a0722
--- /dev/null
+++ b/xos/onboard/fabric/synchronizer/manifest
@@ -0,0 +1,9 @@
+manifest
+fabric_synchronizer_config
+steps/sync_host.yaml
+steps/sync_vroutertenant.py
+start.sh
+stop.sh
+model-deps
+run.sh
+fabric-synchronizer.py
diff --git a/xos/synchronizers/vtr/model-deps b/xos/onboard/fabric/synchronizer/model-deps
similarity index 100%
copy from xos/synchronizers/vtr/model-deps
copy to xos/onboard/fabric/synchronizer/model-deps
diff --git a/xos/synchronizers/fabric/run.sh b/xos/onboard/fabric/synchronizer/run.sh
similarity index 100%
rename from xos/synchronizers/fabric/run.sh
rename to xos/onboard/fabric/synchronizer/run.sh
diff --git a/xos/synchronizers/fabric/start.sh b/xos/onboard/fabric/synchronizer/start.sh
similarity index 100%
rename from xos/synchronizers/fabric/start.sh
rename to xos/onboard/fabric/synchronizer/start.sh
diff --git a/xos/synchronizers/fabric/steps/sync_host.yaml b/xos/onboard/fabric/synchronizer/steps/sync_host.yaml
similarity index 100%
rename from xos/synchronizers/fabric/steps/sync_host.yaml
rename to xos/onboard/fabric/synchronizer/steps/sync_host.yaml
diff --git a/xos/synchronizers/fabric/steps/sync_vroutertenant.py b/xos/onboard/fabric/synchronizer/steps/sync_vroutertenant.py
similarity index 100%
rename from xos/synchronizers/fabric/steps/sync_vroutertenant.py
rename to xos/onboard/fabric/synchronizer/steps/sync_vroutertenant.py
diff --git a/xos/synchronizers/fabric/stop.sh b/xos/onboard/fabric/synchronizer/stop.sh
similarity index 100%
rename from xos/synchronizers/fabric/stop.sh
rename to xos/onboard/fabric/synchronizer/stop.sh
diff --git a/xos/services/fabric/templates/fabricadmin.html b/xos/onboard/fabric/templates/fabricadmin.html
similarity index 100%
rename from xos/services/fabric/templates/fabricadmin.html
rename to xos/onboard/fabric/templates/fabricadmin.html
diff --git a/xos/tosca/resources/fabricservice.py b/xos/onboard/fabric/tosca/resources/fabricservice.py
similarity index 100%
rename from xos/tosca/resources/fabricservice.py
rename to xos/onboard/fabric/tosca/resources/fabricservice.py
diff --git a/xos/services/onos/admin.py b/xos/onboard/onos/admin.py
similarity index 100%
rename from xos/services/onos/admin.py
rename to xos/onboard/onos/admin.py
diff --git a/xos/api/service/onos.py b/xos/onboard/onos/api/service/onos.py
similarity index 100%
rename from xos/api/service/onos.py
rename to xos/onboard/onos/api/service/onos.py
diff --git a/xos/api/tenant/onos/app.py b/xos/onboard/onos/api/tenant/onos/app.py
similarity index 100%
rename from xos/api/tenant/onos/app.py
rename to xos/onboard/onos/api/tenant/onos/app.py
diff --git a/xos/services/onos/models.py b/xos/onboard/onos/models.py
similarity index 100%
rename from xos/services/onos/models.py
rename to xos/onboard/onos/models.py
diff --git a/xos/onboard/onos/onos-onboard.yaml b/xos/onboard/onos/onos-onboard.yaml
new file mode 100644
index 0000000..1338bb6
--- /dev/null
+++ b/xos/onboard/onos/onos-onboard.yaml
@@ -0,0 +1,27 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+ - custom_types/xos.yaml
+
+topology_template:
+ node_templates:
+ servicecontroller#onos:
+ type: tosca.nodes.ServiceController
+ properties:
+ base_url: file:///opt/xos/onboard/onos/
+ # The following will concatenate with base_url automatically, if
+ # base_url is non-null.
+ models: models.py
+ admin: admin.py
+ admin_template: templates/onosadmin.html
+ synchronizer: synchronizer/manifest
+ synchronizer_run: onos-synchronizer.py
+ #tosca_custom_types: exampleservice.yaml
+ tosca_resource: tosca/resources/onosservice.py, tosca/resources/onosapp.py
+ rest_service: subdirectory:vsg api/service/onos.py
+ rest_tenant: subdirectory:onos api/tenant/onos/app.py
+ private_key: file:///opt/xos/key_import/onos_rsa
+ public_key: file:///opt/xos/key_import/onos_rsa.pub
+
diff --git a/xos/onboard/onos/synchronizer/manifest b/xos/onboard/onos/synchronizer/manifest
new file mode 100644
index 0000000..b96216a
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/manifest
@@ -0,0 +1,16 @@
+manifest
+onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
+scripts/dockerip.sh
+steps/sync_onosapp.py
+steps/sync_onosapp_nocontainer.yaml
+steps/sync_onosservice.py
+steps/sync_onosservice.yaml
+steps/sync_onosapp.yaml
+onos-ext-notifier-1.0-SNAPSHOT.oar
+start.sh
+stop.sh
+model-deps
+onos_synchronizer_config
+supervisor/onos-observer.conf
+run.sh
+onos-synchronizer.py
diff --git a/xos/synchronizers/onos/model-deps b/xos/onboard/onos/synchronizer/model-deps
similarity index 100%
rename from xos/synchronizers/onos/model-deps
rename to xos/onboard/onos/synchronizer/model-deps
diff --git a/xos/synchronizers/onos/onos-ext-notifier-1.0-SNAPSHOT.oar b/xos/onboard/onos/synchronizer/onos-ext-notifier-1.0-SNAPSHOT.oar
similarity index 100%
rename from xos/synchronizers/onos/onos-ext-notifier-1.0-SNAPSHOT.oar
rename to xos/onboard/onos/synchronizer/onos-ext-notifier-1.0-SNAPSHOT.oar
Binary files differ
diff --git a/xos/synchronizers/onos/onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar b/xos/onboard/onos/synchronizer/onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
similarity index 100%
rename from xos/synchronizers/onos/onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
rename to xos/onboard/onos/synchronizer/onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
Binary files differ
diff --git a/xos/synchronizers/onos/onos-synchronizer.py b/xos/onboard/onos/synchronizer/onos-synchronizer.py
similarity index 100%
rename from xos/synchronizers/onos/onos-synchronizer.py
rename to xos/onboard/onos/synchronizer/onos-synchronizer.py
diff --git a/xos/synchronizers/onos/onos_synchronizer_config b/xos/onboard/onos/synchronizer/onos_synchronizer_config
similarity index 100%
rename from xos/synchronizers/onos/onos_synchronizer_config
rename to xos/onboard/onos/synchronizer/onos_synchronizer_config
diff --git a/xos/synchronizers/onos/run.sh b/xos/onboard/onos/synchronizer/run.sh
similarity index 100%
rename from xos/synchronizers/onos/run.sh
rename to xos/onboard/onos/synchronizer/run.sh
diff --git a/xos/synchronizers/onos/scripts/dockerip.sh b/xos/onboard/onos/synchronizer/scripts/dockerip.sh
similarity index 100%
rename from xos/synchronizers/onos/scripts/dockerip.sh
rename to xos/onboard/onos/synchronizer/scripts/dockerip.sh
diff --git a/xos/synchronizers/onos/start.sh b/xos/onboard/onos/synchronizer/start.sh
similarity index 100%
rename from xos/synchronizers/onos/start.sh
rename to xos/onboard/onos/synchronizer/start.sh
diff --git a/xos/synchronizers/onos/steps/sync_onosapp.py b/xos/onboard/onos/synchronizer/steps/sync_onosapp.py
similarity index 98%
rename from xos/synchronizers/onos/steps/sync_onosapp.py
rename to xos/onboard/onos/synchronizer/steps/sync_onosapp.py
index 3a9abfc..78a8cc8 100644
--- a/xos/synchronizers/onos/steps/sync_onosapp.py
+++ b/xos/onboard/onos/synchronizer/steps/sync_onosapp.py
@@ -18,7 +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
+from services.volt.models import VOLTService, VOLTDevice, AccessDevice
# hpclibrary will be in steps/..
parentdir = os.path.join(os.path.dirname(__file__),"..")
@@ -31,7 +31,7 @@
observes=ONOSApp
requested_interval=0
template_name = "sync_onosapp.yaml"
- service_key_name = "/opt/xos/synchronizers/onos/onos_key"
+ #service_key_name = "/opt/xos/synchronizers/onos/onos_key"
def __init__(self, *args, **kwargs):
super(SyncONOSApp, self).__init__(*args, **kwargs)
diff --git a/xos/synchronizers/onos/steps/sync_onosapp.yaml b/xos/onboard/onos/synchronizer/steps/sync_onosapp.yaml
similarity index 100%
rename from xos/synchronizers/onos/steps/sync_onosapp.yaml
rename to xos/onboard/onos/synchronizer/steps/sync_onosapp.yaml
diff --git a/xos/synchronizers/onos/steps/sync_onosapp_nocontainer.yaml b/xos/onboard/onos/synchronizer/steps/sync_onosapp_nocontainer.yaml
similarity index 100%
rename from xos/synchronizers/onos/steps/sync_onosapp_nocontainer.yaml
rename to xos/onboard/onos/synchronizer/steps/sync_onosapp_nocontainer.yaml
diff --git a/xos/synchronizers/onos/steps/sync_onosservice.py b/xos/onboard/onos/synchronizer/steps/sync_onosservice.py
similarity index 97%
rename from xos/synchronizers/onos/steps/sync_onosservice.py
rename to xos/onboard/onos/synchronizer/steps/sync_onosservice.py
index 2e6acd9..ce446cf 100644
--- a/xos/synchronizers/onos/steps/sync_onosservice.py
+++ b/xos/onboard/onos/synchronizer/steps/sync_onosservice.py
@@ -24,7 +24,7 @@
observes=ONOSService
requested_interval=0
template_name = "sync_onosservice.yaml"
- service_key_name = "/opt/xos/synchronizers/onos/onos_key"
+ #service_key_name = "/opt/xos/synchronizers/onos/onos_key"
def __init__(self, *args, **kwargs):
super(SyncONOSService, self).__init__(*args, **kwargs)
diff --git a/xos/synchronizers/onos/steps/sync_onosservice.yaml b/xos/onboard/onos/synchronizer/steps/sync_onosservice.yaml
similarity index 100%
rename from xos/synchronizers/onos/steps/sync_onosservice.yaml
rename to xos/onboard/onos/synchronizer/steps/sync_onosservice.yaml
diff --git a/xos/synchronizers/onos/stop.sh b/xos/onboard/onos/synchronizer/stop.sh
similarity index 100%
rename from xos/synchronizers/onos/stop.sh
rename to xos/onboard/onos/synchronizer/stop.sh
diff --git a/xos/synchronizers/onos/supervisor/onos-observer.conf b/xos/onboard/onos/synchronizer/supervisor/onos-observer.conf
similarity index 100%
rename from xos/synchronizers/onos/supervisor/onos-observer.conf
rename to xos/onboard/onos/synchronizer/supervisor/onos-observer.conf
diff --git a/xos/services/onos/templates/onosadmin.html b/xos/onboard/onos/templates/onosadmin.html
similarity index 100%
rename from xos/services/onos/templates/onosadmin.html
rename to xos/onboard/onos/templates/onosadmin.html
diff --git a/xos/tosca/resources/onosapp.py b/xos/onboard/onos/tosca/resources/onosapp.py
similarity index 100%
rename from xos/tosca/resources/onosapp.py
rename to xos/onboard/onos/tosca/resources/onosapp.py
diff --git a/xos/tosca/resources/onosservice.py b/xos/onboard/onos/tosca/resources/onosservice.py
similarity index 100%
rename from xos/tosca/resources/onosservice.py
rename to xos/onboard/onos/tosca/resources/onosservice.py
diff --git a/xos/onboard/volt/admin.py b/xos/onboard/volt/admin.py
new file mode 100644
index 0000000..cf5dfa6
--- /dev/null
+++ b/xos/onboard/volt/admin.py
@@ -0,0 +1,237 @@
+from django.contrib import admin
+
+from services.volt.models import *
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+from django.utils import timezone
+from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, ServicePrivilegeInline, TenantRootTenantInline, TenantRootPrivilegeInline
+from core.middleware import get_request
+
+from functools import update_wrapper
+from django.contrib.admin.views.main import ChangeList
+from django.core.urlresolvers import reverse
+from django.contrib.admin.utils import quote
+
+#-----------------------------------------------------------------------------
+# vOLT
+#-----------------------------------------------------------------------------
+
+class VOLTServiceAdmin(ReadOnlyAwareAdmin):
+ model = VOLTService
+ verbose_name = "vOLT Service"
+ verbose_name_plural = "vOLT Service"
+ 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" ], 'classes':['suit-tab suit-tab-general']})]
+ readonly_fields = ('backend_status_text', )
+ inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+
+ extracontext_registered_admins = True
+
+ user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+ suit_form_tabs =(('general', 'vOLT Service Details'),
+ ('administration', 'Administration'),
+ #('tools', 'Tools'),
+ ('slices','Slices'),
+ ('serviceattrs','Additional Attributes'),
+ ('serviceprivileges','Privileges'),
+ )
+
+ suit_form_includes = (('voltadmin.html', 'top', 'administration'),
+ ) #('hpctools.html', 'top', 'tools') )
+
+ def queryset(self, request):
+ return VOLTService.get_service_objects_by_user(request.user)
+
+class VOLTTenantForm(forms.ModelForm):
+ s_tag = forms.CharField()
+ c_tag = forms.CharField()
+ creator = forms.ModelChoiceField(queryset=User.objects.all())
+
+ def __init__(self,*args,**kwargs):
+ super (VOLTTenantForm,self ).__init__(*args,**kwargs)
+ self.fields['kind'].widget.attrs['readonly'] = True
+ self.fields['provider_service'].queryset = VOLTService.get_service_objects().all()
+ if self.instance:
+ # fields for the attributes
+ self.fields['c_tag'].initial = self.instance.c_tag
+ self.fields['s_tag'].initial = self.instance.s_tag
+ self.fields['creator'].initial = self.instance.creator
+ if (not self.instance) or (not self.instance.pk):
+ # default fields for an 'add' form
+ self.fields['kind'].initial = VOLT_KIND
+ self.fields['creator'].initial = get_request().user
+ if VOLTService.get_service_objects().exists():
+ self.fields["provider_service"].initial = VOLTService.get_service_objects().all()[0]
+
+ def save(self, commit=True):
+ self.instance.s_tag = self.cleaned_data.get("s_tag")
+ self.instance.c_tag = self.cleaned_data.get("c_tag")
+ self.instance.creator = self.cleaned_data.get("creator")
+ return super(VOLTTenantForm, self).save(commit=commit)
+
+ class Meta:
+ model = VOLTTenant
+
+class VOLTTenantAdmin(ReadOnlyAwareAdmin):
+ list_display = ('backend_status_icon', 'id', 'service_specific_id', 's_tag', 'c_tag', 'subscriber_root' )
+ list_display_links = ('backend_status_icon', 'id')
+ fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'provider_service', 'subscriber_root', 'service_specific_id', # 'service_specific_attribute',
+ 's_tag', 'c_tag', 'creator'],
+ 'classes':['suit-tab suit-tab-general']})]
+ readonly_fields = ('backend_status_text', 'service_specific_attribute')
+ form = VOLTTenantForm
+
+ suit_form_tabs = (('general','Details'),)
+
+ 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'))
+
+# -------------------------------------------
+# CORDSubscriberRoot
+# -------------------------------------------
+
+class VOLTTenantInline(XOSTabularInline):
+ model = VOLTTenant
+ fields = ['provider_service', 'subscriber_root', 'service_specific_id']
+ readonly_fields = ['provider_service', 'subscriber_root', 'service_specific_id']
+ extra = 0
+ max_num = 0
+ suit_classes = 'suit-tab suit-tab-volttenants'
+ fk_name = 'subscriber_root'
+ verbose_name = 'subscribed tenant'
+ verbose_name_plural = 'subscribed tenants'
+
+ @property
+ def selflink_reverse_path(self):
+ return "admin:cord_volttenant_change"
+
+ def queryset(self, request):
+ qs = super(VOLTTenantInline, self).queryset(request)
+ return qs.filter(kind=VOLT_KIND)
+
+class CordSubscriberRootForm(forms.ModelForm):
+ url_filter_level = forms.CharField(required = False)
+ uplink_speed = forms.CharField(required = False)
+ downlink_speed = forms.CharField(required = False)
+ status = forms.ChoiceField(choices=CordSubscriberRoot.status_choices, required=True)
+ enable_uverse = forms.BooleanField(required=False)
+ cdn_enable = forms.BooleanField(required=False)
+
+ def __init__(self,*args,**kwargs):
+ super (CordSubscriberRootForm,self ).__init__(*args,**kwargs)
+ self.fields['kind'].widget.attrs['readonly'] = True
+ if self.instance:
+ self.fields['url_filter_level'].initial = self.instance.url_filter_level
+ self.fields['uplink_speed'].initial = self.instance.uplink_speed
+ self.fields['downlink_speed'].initial = self.instance.downlink_speed
+ self.fields['status'].initial = self.instance.status
+ self.fields['enable_uverse'].initial = self.instance.enable_uverse
+ self.fields['cdn_enable'].initial = self.instance.cdn_enable
+ if (not self.instance) or (not self.instance.pk):
+ # default fields for an 'add' form
+ self.fields['kind'].initial = CORD_SUBSCRIBER_KIND
+ self.fields['uplink_speed'].initial = CordSubscriberRoot.get_default_attribute("uplink_speed")
+ self.fields['downlink_speed'].initial = CordSubscriberRoot.get_default_attribute("downlink_speed")
+ self.fields['status'].initial = CordSubscriberRoot.get_default_attribute("status")
+ self.fields['enable_uverse'].initial = CordSubscriberRoot.get_default_attribute("enable_uverse")
+ self.fields['cdn_enable'].initial = CordSubscriberRoot.get_default_attribute("cdn_enable")
+
+ def save(self, commit=True):
+ self.instance.url_filter_level = self.cleaned_data.get("url_filter_level")
+ self.instance.uplink_speed = self.cleaned_data.get("uplink_speed")
+ self.instance.downlink_speed = self.cleaned_data.get("downlink_speed")
+ self.instance.status = self.cleaned_data.get("status")
+ self.instance.enable_uverse = self.cleaned_data.get("enable_uverse")
+ self.instance.cdn_enable = self.cleaned_data.get("cdn_enable")
+ return super(CordSubscriberRootForm, self).save(commit=commit)
+
+ class Meta:
+ model = CordSubscriberRoot
+
+class CordSubscriberRootAdmin(ReadOnlyAwareAdmin):
+ list_display = ('backend_status_icon', 'id', 'name', )
+ list_display_links = ('backend_status_icon', 'id', 'name', )
+ fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'name', 'service_specific_id', # 'service_specific_attribute',
+ 'url_filter_level', "uplink_speed", "downlink_speed", "status", "enable_uverse", "cdn_enable"],
+ 'classes':['suit-tab suit-tab-general']})]
+ readonly_fields = ('backend_status_text', 'service_specific_attribute',)
+ form = CordSubscriberRootForm
+ inlines = (VOLTTenantInline, TenantRootPrivilegeInline)
+
+ suit_form_tabs =(('general', 'Cord Subscriber Root Details'),
+ ('volttenants','VOLT Tenancy'),
+ ('tenantrootprivileges','Privileges')
+ )
+
+ def queryset(self, request):
+ return CordSubscriberRoot.get_tenant_objects_by_user(request.user)
+
+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(CordSubscriberRoot, CordSubscriberRootAdmin)
+
diff --git a/xos/api/tenant/cord/subscriber.py b/xos/onboard/volt/api/tenant/cord/subscriber.py
similarity index 99%
rename from xos/api/tenant/cord/subscriber.py
rename to xos/onboard/volt/api/tenant/cord/subscriber.py
index eab6cb3..52f9b63 100644
--- a/xos/api/tenant/cord/subscriber.py
+++ b/xos/onboard/volt/api/tenant/cord/subscriber.py
@@ -10,7 +10,7 @@
from core.models import *
from django.forms import widgets
from django.conf.urls import patterns, url
-from services.cord.models import VOLTTenant, VBNGTenant, CordSubscriberRoot
+from services.volt.models import VOLTTenant, CordSubscriberRoot
from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
from django.shortcuts import get_object_or_404
from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
diff --git a/xos/api/tenant/cord/volt.py b/xos/onboard/volt/api/tenant/cord/volt.py
similarity index 97%
rename from xos/api/tenant/cord/volt.py
rename to xos/onboard/volt/api/tenant/cord/volt.py
index e17cf26..5c9634a 100644
--- a/xos/api/tenant/cord/volt.py
+++ b/xos/onboard/volt/api/tenant/cord/volt.py
@@ -6,7 +6,7 @@
from rest_framework import status
from core.models import *
from django.forms import widgets
-from services.cord.models import VOLTTenant, VOLTService, CordSubscriberRoot
+from services.volt.models import VOLTTenant, VOLTService, CordSubscriberRoot
from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
diff --git a/xos/onboard/volt/models.py b/xos/onboard/volt/models.py
new file mode 100644
index 0000000..8f3cc1f
--- /dev/null
+++ b/xos/onboard/volt/models.py
@@ -0,0 +1,367 @@
+from django.db import models
+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
+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 services.vrouter.models import VRouterService, VRouterTenant
+import traceback
+from xos.exceptions import *
+from xos.config import Config
+
+class ConfigurationError(Exception):
+ pass
+
+VOLT_KIND = "vOLT"
+CORD_SUBSCRIBER_KIND = "CordSubscriberRoot"
+
+CORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
+
+# -------------------------------------------
+# CordSubscriberRoot
+# -------------------------------------------
+
+class CordSubscriberRoot(Subscriber):
+ class Meta:
+ proxy = True
+
+ KIND = CORD_SUBSCRIBER_KIND
+
+ status_choices = (("enabled", "Enabled"),
+ ("suspended", "Suspended"),
+ ("delinquent", "Delinquent"),
+ ("copyrightviolation", "Copyright Violation"))
+
+ # 'simple_attributes' will be expanded into properties and setters that
+ # store the attribute using self.set_attribute / self.get_attribute.
+
+ simple_attributes = ( ("firewall_enable", False),
+ ("firewall_rules", "accept all anywhere anywhere"),
+ ("url_filter_enable", False),
+ ("url_filter_rules", "allow all"),
+ ("url_filter_level", "PG"),
+ ("cdn_enable", False),
+ ("devices", []),
+ ("is_demo_user", False),
+
+ ("uplink_speed", 1000000000), # 1 gigabit, a reasonable default?
+ ("downlink_speed", 1000000000),
+ ("enable_uverse", True) )
+
+ default_attributes = {"status": "enabled"}
+
+ sync_attributes = ("firewall_enable",
+ "firewall_rules",
+ "url_filter_enable",
+ "url_filter_rules",
+ "cdn_enable",
+ "uplink_speed",
+ "downlink_speed",
+ "enable_uverse",
+ "status")
+
+ def __init__(self, *args, **kwargs):
+ super(CordSubscriberRoot, self).__init__(*args, **kwargs)
+ self.cached_volt = None
+ self._initial_url_filter_enable = self.url_filter_enable
+
+ @property
+ def volt(self):
+ volt = self.get_newest_subscribed_tenant(VOLTTenant)
+ if not volt:
+ return None
+
+ # always return the same object when possible
+ if (self.cached_volt) and (self.cached_volt.id == volt.id):
+ return self.cached_volt
+
+ #volt.caller = self.creator
+ self.cached_volt = volt
+ return volt
+
+ @property
+ def status(self):
+ return self.get_attribute("status", self.default_attributes["status"])
+
+ @status.setter
+ def status(self, value):
+ if not value in [x[0] for x in self.status_choices]:
+ raise Exception("invalid status %s" % value)
+ self.set_attribute("status", value)
+
+ def find_device(self, mac):
+ for device in self.devices:
+ if device["mac"] == mac:
+ return device
+ return None
+
+ def update_device(self, mac, **kwargs):
+ # kwargs may be "level" or "mac"
+ # Setting one of these to None will cause None to be stored in the db
+ devices = self.devices
+ for device in devices:
+ if device["mac"] == mac:
+ for arg in kwargs.keys():
+ device[arg] = kwargs[arg]
+ self.devices = devices
+ return device
+ raise ValueError("Device with mac %s not found" % mac)
+
+ def create_device(self, **kwargs):
+ if "mac" not in kwargs:
+ raise XOSMissingField("The mac field is required")
+
+ if self.find_device(kwargs['mac']):
+ raise XOSDuplicateKey("Device with mac %s already exists" % kwargs["mac"])
+
+ device = kwargs.copy()
+
+ devices = self.devices
+ devices.append(device)
+ self.devices = devices
+
+ return device
+
+ def delete_device(self, mac):
+ devices = self.devices
+ for device in devices:
+ if device["mac"]==mac:
+ devices.remove(device)
+ self.devices = devices
+ return
+
+ raise ValueError("Device with mac %s not found" % mac)
+
+ #--------------------------------------------------------------------------
+ # Deprecated -- devices used to be called users
+
+ def find_user(self, uid):
+ return self.find_device(uid)
+
+ def update_user(self, uid, **kwargs):
+ return self.update_device(uid, **kwargs)
+
+ def create_user(self, **kwargs):
+ return self.create_device(**kwargs)
+
+ def delete_user(self, uid):
+ return self.delete_user(uid)
+
+ # ------------------------------------------------------------------------
+
+ @property
+ def services(self):
+ return {"cdn": self.cdn_enable,
+ "url_filter": self.url_filter_enable,
+ "firewall": self.firewall_enable}
+
+ @services.setter
+ def services(self, value):
+ pass
+
+ def save(self, *args, **kwargs):
+ self.validate_unique_service_specific_id(none_okay=True)
+ if (not hasattr(self, 'caller') or not self.caller.is_admin):
+ if (self.has_field_changed("service_specific_id")):
+ raise XOSPermissionDenied("You do not have permission to change service_specific_id")
+ super(CordSubscriberRoot, self).save(*args, **kwargs)
+ if (self.volt) and (self.volt.vcpe): # and (self._initial_url_filter_enabled != self.url_filter_enable):
+ # 1) trigger manage_bbs_account to run
+ # 2) trigger vcpe observer to wake up
+ self.volt.vcpe.save()
+
+CordSubscriberRoot.setup_simple_attributes()
+
+# -------------------------------------------
+# VOLT
+# -------------------------------------------
+
+class VOLTService(Service):
+ KIND = VOLT_KIND
+
+ class Meta:
+ app_label = "volt"
+ verbose_name = "vOLT Service"
+
+class VOLTTenant(Tenant):
+ KIND = VOLT_KIND
+
+ class Meta:
+ app_label = "volt"
+ 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:
+ self._meta.get_field("provider_service").default = volt_services[0].id
+ super(VOLTTenant, self).__init__(*args, **kwargs)
+ self.cached_vcpe = None
+
+ @property
+ def vcpe(self):
+ from services.vsg.models import VSGTenant
+ vcpe = self.get_newest_subscribed_tenant(VSGTenant)
+ if not vcpe:
+ return None
+
+ # always return the same object when possible
+ if (self.cached_vcpe) and (self.cached_vcpe.id == vcpe.id):
+ return self.cached_vcpe
+
+ vcpe.caller = self.creator
+ self.cached_vcpe = vcpe
+ return vcpe
+
+ @vcpe.setter
+ def vcpe(self, value):
+ raise XOSConfigurationError("vOLT.vCPE cannot be set this way -- create a new vCPE object and set its subscriber_tenant instead")
+
+ @property
+ def subscriber(self):
+ if not self.subscriber_root:
+ return None
+ subs = CordSubscriberRoot.objects.filter(id=self.subscriber_root.id)
+ if not subs:
+ return None
+ return subs[0]
+
+ def manage_vcpe(self):
+ # Each VOLT object owns exactly one VCPE object
+
+ if self.deleted:
+ return
+
+ if self.vcpe is None:
+ from services.vsg.models import VSGService, VSGTenant
+ vsgServices = VSGService.get_service_objects().all()
+ if not vsgServices:
+ raise XOSConfigurationError("No VSG Services available")
+
+ vcpe = VSGTenant(provider_service = vsgServices[0],
+ subscriber_tenant = self)
+ vcpe.caller = self.creator
+ vcpe.save()
+
+ def manage_subscriber(self):
+ if (self.subscriber_root is None):
+ # The vOLT is not connected to a Subscriber, so either find an
+ # existing subscriber with the same SSID, or autogenerate a new
+ # subscriber.
+ #
+ # TODO: This probably goes away when we rethink the ONOS-to-XOS
+ # vOLT API.
+
+ subs = CordSubscriberRoot.get_tenant_objects().filter(service_specific_id = self.service_specific_id)
+ if subs:
+ sub = subs[0]
+ else:
+ sub = CordSubscriberRoot(service_specific_id = self.service_specific_id,
+ name = "autogenerated-for-vOLT-%s" % self.id)
+ sub.save()
+ self.subscriber_root = sub
+ self.save()
+
+ def cleanup_vcpe(self):
+ if self.vcpe:
+ # print "XXX cleanup vcpe", self.vcpe
+ self.vcpe.delete()
+
+ def cleanup_orphans(self):
+ from services.vsg.models import VSGTenant
+ # ensure vOLT only has one vCPE
+ cur_vcpe = self.vcpe
+ for vcpe in list(self.get_subscribed_tenants(VSGTenant)):
+ if (not cur_vcpe) or (vcpe.id != cur_vcpe.id):
+ # print "XXX clean up orphaned vcpe", vcpe
+ vcpe.delete()
+
+ def save(self, *args, **kwargs):
+ # VOLTTenant probably doesn't need a SSID anymore; that will be handled
+ # by CORDSubscriberRoot...
+ # self.validate_unique_service_specific_id()
+
+ if (self.subscriber_root is not None):
+ subs = self.subscriber_root.get_subscribed_tenants(VOLTTenant)
+ if (subs) and (self not in subs):
+ raise XOSDuplicateKey("Subscriber should only be linked to one vOLT")
+
+ if not self.creator:
+ if not getattr(self, "caller", None):
+ # caller must be set when creating a vCPE since it creates a slice
+ raise XOSProgrammingError("VOLTTenant's self.caller was not set")
+ self.creator = self.caller
+ if not self.creator:
+ raise XOSProgrammingError("VOLTTenant's self.creator was not set")
+
+ super(VOLTTenant, self).save(*args, **kwargs)
+ model_policy_volt(self.pk)
+
+ def delete(self, *args, **kwargs):
+ self.cleanup_vcpe()
+ super(VOLTTenant, self).delete(*args, **kwargs)
+
+def model_policy_volt(pk):
+ # TODO: this should be made in to a real model_policy
+ with transaction.atomic():
+ volt = VOLTTenant.objects.select_for_update().filter(pk=pk)
+ if not volt:
+ return
+ volt = volt[0]
+ volt.manage_vcpe()
+ volt.manage_subscriber()
+ volt.cleanup_orphans()
+
+class VOLTDevice(PlCoreBase):
+ class Meta:
+ app_label = "volt"
+
+ 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 = "volt"
+
+ 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 = "volt"
+
+ 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 = "volt"
+
+ 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)
+
+
+
diff --git a/xos/services/cord/templates/voltadmin.html b/xos/onboard/volt/templates/voltadmin.html
similarity index 100%
rename from xos/services/cord/templates/voltadmin.html
rename to xos/onboard/volt/templates/voltadmin.html
diff --git a/xos/tosca/resources/CORDSubscriber.py b/xos/onboard/volt/tosca/resources/CORDSubscriber.py
similarity index 93%
rename from xos/tosca/resources/CORDSubscriber.py
rename to xos/onboard/volt/tosca/resources/CORDSubscriber.py
index f013032..5cdb2ef 100644
--- a/xos/tosca/resources/CORDSubscriber.py
+++ b/xos/onboard/volt/tosca/resources/CORDSubscriber.py
@@ -7,7 +7,7 @@
import pdb
from core.models import User, TenantRootPrivilege, TenantRootRole
-from services.cord.models import CordSubscriberRoot
+from services.volt.models import CordSubscriberRoot
from xosresource import XOSResource
diff --git a/xos/tosca/resources/CORDUser.py b/xos/onboard/volt/tosca/resources/CORDUser.py
similarity index 96%
rename from xos/tosca/resources/CORDUser.py
rename to xos/onboard/volt/tosca/resources/CORDUser.py
index ff2dc8f..d1ae1cc 100644
--- a/xos/tosca/resources/CORDUser.py
+++ b/xos/onboard/volt/tosca/resources/CORDUser.py
@@ -7,7 +7,7 @@
import pdb
from core.models import User
-from services.cord.models import CordSubscriberRoot
+from services.volt.models import CordSubscriberRoot
from xosresource import XOSResource
diff --git a/xos/tosca/resources/VOLTTenant.py b/xos/onboard/volt/tosca/resources/VOLTTenant.py
similarity index 96%
rename from xos/tosca/resources/VOLTTenant.py
rename to xos/onboard/volt/tosca/resources/VOLTTenant.py
index ae1692d..cbc3837 100644
--- a/xos/tosca/resources/VOLTTenant.py
+++ b/xos/onboard/volt/tosca/resources/VOLTTenant.py
@@ -7,7 +7,7 @@
import pdb
from core.models import User
-from services.cord.models import VOLTTenant, VOLTService, CordSubscriberRoot, VOLT_KIND
+from services.volt.models import VOLTTenant, VOLTService, CordSubscriberRoot, VOLT_KIND
from xosresource import XOSResource
diff --git a/xos/tosca/resources/accessagent.py b/xos/onboard/volt/tosca/resources/accessagent.py
similarity index 96%
rename from xos/tosca/resources/accessagent.py
rename to xos/onboard/volt/tosca/resources/accessagent.py
index 368ce55..e40a1cb 100644
--- a/xos/tosca/resources/accessagent.py
+++ b/xos/onboard/volt/tosca/resources/accessagent.py
@@ -5,7 +5,7 @@
sys.path.append("/opt/tosca")
from translator.toscalib.tosca_template import ToscaTemplate
-from services.cord.models import AccessAgent, VOLTDevice, VOLTService, AgentPortMapping
+from services.volt.models import AccessAgent, VOLTDevice, VOLTService, AgentPortMapping
from xosresource import XOSResource
class XOSAccessAgent(XOSResource):
diff --git a/xos/tosca/resources/accessdevice.py b/xos/onboard/volt/tosca/resources/accessdevice.py
similarity index 95%
rename from xos/tosca/resources/accessdevice.py
rename to xos/onboard/volt/tosca/resources/accessdevice.py
index 94deb86..f31b37a 100644
--- a/xos/tosca/resources/accessdevice.py
+++ b/xos/onboard/volt/tosca/resources/accessdevice.py
@@ -5,7 +5,7 @@
sys.path.append("/opt/tosca")
from translator.toscalib.tosca_template import ToscaTemplate
-from services.cord.models import AccessDevice, VOLTDevice
+from services.volt.models import AccessDevice, VOLTDevice
from xosresource import XOSResource
class XOSAccessDevice(XOSResource):
diff --git a/xos/tosca/resources/voltdevice.py b/xos/onboard/volt/tosca/resources/voltdevice.py
similarity index 96%
rename from xos/tosca/resources/voltdevice.py
rename to xos/onboard/volt/tosca/resources/voltdevice.py
index f1c6830..9665b85 100644
--- a/xos/tosca/resources/voltdevice.py
+++ b/xos/onboard/volt/tosca/resources/voltdevice.py
@@ -5,7 +5,7 @@
sys.path.append("/opt/tosca")
from translator.toscalib.tosca_template import ToscaTemplate
-from services.cord.models import VOLTDevice, VOLTService, AccessDevice, AccessAgent
+from services.volt.models import VOLTDevice, VOLTService, AccessDevice, AccessAgent
from xosresource import XOSResource
class XOSVOLTDevice(XOSResource):
diff --git a/xos/tosca/resources/voltservice.py b/xos/onboard/volt/tosca/resources/voltservice.py
similarity index 89%
rename from xos/tosca/resources/voltservice.py
rename to xos/onboard/volt/tosca/resources/voltservice.py
index 57cf846..9df4259 100644
--- a/xos/tosca/resources/voltservice.py
+++ b/xos/onboard/volt/tosca/resources/voltservice.py
@@ -5,7 +5,7 @@
sys.path.append("/opt/tosca")
from translator.toscalib.tosca_template import ToscaTemplate
-from services.cord.models import VOLTService
+from services.volt.models import VOLTService
from service import XOSService
diff --git a/xos/onboard/volt/volt-onboard.yaml b/xos/onboard/volt/volt-onboard.yaml
new file mode 100644
index 0000000..e91ea93
--- /dev/null
+++ b/xos/onboard/volt/volt-onboard.yaml
@@ -0,0 +1,24 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+ - custom_types/xos.yaml
+
+topology_template:
+ node_templates:
+ servicecontroller#volt:
+ type: tosca.nodes.ServiceController
+ properties:
+ base_url: file:///opt/xos/onboard/volt/
+ # The following will concatenate with base_url automatically, if
+ # base_url is non-null.
+ models: models.py
+ admin: admin.py
+ admin_template: templates/voltadmin.html
+ #synchronizer: synchronizer/manifest
+ tosca_resource: tosca/resources/voltdevice.py, tosca/resources/voltservice.py, tosca/resources/CORDSubscriber.py, tosca/resources/CORDUser.py, tosca/resources/VOLTTenant.py, tosca/resources/accessagent.py, tosca/resources/accessdevice.py
+ rest_tenant: subdirectory:cord api/tenant/cord/volt.py, subdirectory:cord api/tenant/cord/subscriber.py
+ private_key: file:///opt/xos/key_import/volt_rsa
+ public_key: file:///opt/xos/key_import/volt_rsa.pub
+
diff --git a/xos/services/vrouter/admin.py b/xos/onboard/vrouter/admin.py
similarity index 100%
rename from xos/services/vrouter/admin.py
rename to xos/onboard/vrouter/admin.py
diff --git a/xos/services/vrouter/models.py b/xos/onboard/vrouter/models.py
similarity index 96%
rename from xos/services/vrouter/models.py
rename to xos/onboard/vrouter/models.py
index 05b57e2..d302b13 100644
--- a/xos/services/vrouter/models.py
+++ b/xos/onboard/vrouter/models.py
@@ -15,8 +15,12 @@
class ConfigurationError(Exception):
pass
+
VROUTER_KIND = "vROUTER"
+# NOTE: don't change VROUTER_KIND unless you also change the reference to it
+# in tosca/resources/network.py
+
CORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
class VRouterService(Service):
diff --git a/xos/services/vrouter/templates/vrouteradmin.html b/xos/onboard/vrouter/templates/vrouteradmin.html
similarity index 100%
rename from xos/services/vrouter/templates/vrouteradmin.html
rename to xos/onboard/vrouter/templates/vrouteradmin.html
diff --git a/xos/tosca/resources/vrouterservice.py b/xos/onboard/vrouter/tosca/resources/vrouterservice.py
similarity index 100%
rename from xos/tosca/resources/vrouterservice.py
rename to xos/onboard/vrouter/tosca/resources/vrouterservice.py
diff --git a/xos/onboard/vrouter/vrouter-onboard.yaml b/xos/onboard/vrouter/vrouter-onboard.yaml
new file mode 100644
index 0000000..e956c96
--- /dev/null
+++ b/xos/onboard/vrouter/vrouter-onboard.yaml
@@ -0,0 +1,20 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the vRouter SErvice
+
+imports:
+ - custom_types/xos.yaml
+
+topology_template:
+ node_templates:
+ servicecontroller#vrouter:
+ type: tosca.nodes.ServiceController
+ properties:
+ base_url: file:///opt/xos/onboard/vrouter/
+ # The following will concatenate with base_url automatically, if
+ # base_url is non-null.
+ models: models.py
+ admin: admin.py
+ admin_template: templates/vrouteradmin.html
+ tosca_resource: tosca/resources/vrouterservice.py
+
diff --git a/xos/onboard/vsg/admin.py b/xos/onboard/vsg/admin.py
new file mode 100644
index 0000000..92fa51d
--- /dev/null
+++ b/xos/onboard/vsg/admin.py
@@ -0,0 +1,150 @@
+from django.contrib import admin
+
+from services.vsg.models import *
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+from django.utils import timezone
+from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, ServicePrivilegeInline, TenantRootTenantInline, TenantRootPrivilegeInline
+from core.middleware import get_request
+
+from functools import update_wrapper
+from django.contrib.admin.views.main import ChangeList
+from django.core.urlresolvers import reverse
+from django.contrib.admin.utils import quote
+
+#-----------------------------------------------------------------------------
+# vSG
+#-----------------------------------------------------------------------------
+
+class VSGServiceForm(forms.ModelForm):
+ bbs_api_hostname = forms.CharField(required=False)
+ bbs_api_port = forms.IntegerField(required=False)
+ bbs_server = forms.CharField(required=False)
+ backend_network_label = forms.CharField(required=False)
+ bbs_slice = forms.ModelChoiceField(queryset=Slice.objects.all(), required=False)
+ dns_servers = forms.CharField(required=False)
+ url_filter_kind = forms.ChoiceField(choices=VSGService.URL_FILTER_KIND_CHOICES, required=False)
+ node_label = forms.CharField(required=False)
+
+ def __init__(self,*args,**kwargs):
+ super (VSGServiceForm,self ).__init__(*args,**kwargs)
+ if self.instance:
+ self.fields['bbs_api_hostname'].initial = self.instance.bbs_api_hostname
+ self.fields['bbs_api_port'].initial = self.instance.bbs_api_port
+ self.fields['bbs_server'].initial = self.instance.bbs_server
+ self.fields['backend_network_label'].initial = self.instance.backend_network_label
+ self.fields['bbs_slice'].initial = self.instance.bbs_slice
+ self.fields['dns_servers'].initial = self.instance.dns_servers
+ self.fields['url_filter_kind']. initial = self.instance.url_filter_kind
+ self.fields['node_label'].initial = self.instance.node_label
+
+ def save(self, commit=True):
+ self.instance.bbs_api_hostname = self.cleaned_data.get("bbs_api_hostname")
+ self.instance.bbs_api_port = self.cleaned_data.get("bbs_api_port")
+ self.instance.bbs_server = self.cleaned_data.get("bbs_server")
+ self.instance.backend_network_label = self.cleaned_data.get("backend_network_label")
+ self.instance.bbs_slice = self.cleaned_data.get("bbs_slice")
+ self.instance.dns_servers = self.cleaned_data.get("dns_servers")
+ self.instance.url_filter_kind = self.cleaned_data.get("url_filter_kind")
+ self.instance.node_label = self.cleaned_data.get("node_label")
+ return super(VSGServiceForm, self).save(commit=commit)
+
+ class Meta:
+ model = VSGService
+
+class VSGServiceAdmin(ReadOnlyAwareAdmin):
+ model = VSGService
+ verbose_name = "vSG Service"
+ verbose_name_plural = "vSG Service"
+ 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", "service_specific_attribute", "node_label"],
+ 'classes':['suit-tab suit-tab-general']}),
+ ("backend config", {'fields': [ "backend_network_label", "url_filter_kind", "bbs_api_hostname", "bbs_api_port", "bbs_server", "bbs_slice"],
+ 'classes':['suit-tab suit-tab-backend']}),
+ ("vSG config", {'fields': ["dns_servers"],
+ 'classes':['suit-tab suit-tab-vsg']}) ]
+ readonly_fields = ('backend_status_text', "service_specific_attribute")
+ inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+ form = VSGServiceForm
+
+ extracontext_registered_admins = True
+
+ user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+ suit_form_tabs =(('general', 'Service Details'),
+ ('backend', 'Backend Config'),
+ ('vsg', 'vSG Config'),
+ ('administration', 'Administration'),
+ #('tools', 'Tools'),
+ ('slices','Slices'),
+ ('serviceattrs','Additional Attributes'),
+ ('serviceprivileges','Privileges') ,
+ )
+
+ suit_form_includes = (('vcpeadmin.html', 'top', 'administration'),
+ ) #('hpctools.html', 'top', 'tools') )
+
+ def queryset(self, request):
+ return VSGService.get_service_objects_by_user(request.user)
+
+class VSGTenantForm(forms.ModelForm):
+ bbs_account = forms.CharField(required=False)
+ creator = forms.ModelChoiceField(queryset=User.objects.all())
+ instance = forms.ModelChoiceField(queryset=Instance.objects.all(),required=False)
+ last_ansible_hash = forms.CharField(required=False)
+ wan_container_ip = forms.CharField(required=False)
+ wan_container_mac = forms.CharField(required=False)
+
+ def __init__(self,*args,**kwargs):
+ super (VSGTenantForm,self ).__init__(*args,**kwargs)
+ self.fields['kind'].widget.attrs['readonly'] = True
+ self.fields['provider_service'].queryset = VSGService.get_service_objects().all()
+ if self.instance:
+ # fields for the attributes
+ self.fields['bbs_account'].initial = self.instance.bbs_account
+ self.fields['creator'].initial = self.instance.creator
+ self.fields['instance'].initial = self.instance.instance
+ self.fields['last_ansible_hash'].initial = self.instance.last_ansible_hash
+ self.fields['wan_container_ip'].initial = self.instance.wan_container_ip
+ self.fields['wan_container_mac'].initial = self.instance.wan_container_mac
+ if (not self.instance) or (not self.instance.pk):
+ # default fields for an 'add' form
+ self.fields['kind'].initial = VCPE_KIND
+ self.fields['creator'].initial = get_request().user
+ if VSGService.get_service_objects().exists():
+ self.fields["provider_service"].initial = VSGService.get_service_objects().all()[0]
+
+ def save(self, commit=True):
+ self.instance.creator = self.cleaned_data.get("creator")
+ self.instance.instance = self.cleaned_data.get("instance")
+ self.instance.last_ansible_hash = self.cleaned_data.get("last_ansible_hash")
+ return super(VSGTenantForm, self).save(commit=commit)
+
+ class Meta:
+ model = VSGTenant
+
+class VSGTenantAdmin(ReadOnlyAwareAdmin):
+ list_display = ('backend_status_icon', 'id', 'subscriber_tenant' )
+ list_display_links = ('backend_status_icon', 'id')
+ fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'provider_service', 'subscriber_tenant', 'service_specific_id', # 'service_specific_attribute',
+ 'wan_container_ip', 'wan_container_mac', 'bbs_account', 'creator', 'instance', 'last_ansible_hash'],
+ 'classes':['suit-tab suit-tab-general']})]
+ readonly_fields = ('backend_status_text', 'service_specific_attribute', 'bbs_account', 'wan_container_ip', 'wan_container_mac')
+ form = VSGTenantForm
+
+ suit_form_tabs = (('general','Details'),)
+
+ def queryset(self, request):
+ return VSGTenant.get_tenant_objects_by_user(request.user)
+
+
+admin.site.register(VSGService, VSGServiceAdmin)
+admin.site.register(VSGTenant, VSGTenantAdmin)
+
diff --git a/xos/api/service/vsg/vsgservice.py b/xos/onboard/vsg/api/service/vsg/vsgservice.py
similarity index 98%
rename from xos/api/service/vsg/vsgservice.py
rename to xos/onboard/vsg/api/service/vsg/vsgservice.py
index 9ab4756..a04fb3e 100644
--- a/xos/api/service/vsg/vsgservice.py
+++ b/xos/onboard/vsg/api/service/vsg/vsgservice.py
@@ -10,7 +10,7 @@
from core.models import *
from django.forms import widgets
from django.conf.urls import patterns, url
-from services.cord.models import VSGService
+from services.vsg.models import VSGService
from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
from django.shortcuts import get_object_or_404
from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
diff --git a/xos/api/tenant/cord/vsg.py b/xos/onboard/vsg/api/tenant/cord/vsg.py
similarity index 95%
rename from xos/api/tenant/cord/vsg.py
rename to xos/onboard/vsg/api/tenant/cord/vsg.py
index 6807e98..c6a4247 100644
--- a/xos/api/tenant/cord/vsg.py
+++ b/xos/onboard/vsg/api/tenant/cord/vsg.py
@@ -6,7 +6,7 @@
from rest_framework import status
from core.models import *
from django.forms import widgets
-from services.cord.models import VSGTenant, VSGService, CordSubscriberRoot
+from services.vsg.models import VSGTenant, VSGService
from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
diff --git a/xos/onboard/vsg/models.py b/xos/onboard/vsg/models.py
new file mode 100644
index 0000000..ad25c98
--- /dev/null
+++ b/xos/onboard/vsg/models.py
@@ -0,0 +1,448 @@
+from django.db import models
+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
+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 services.vrouter.models import VRouterService, VRouterTenant
+import traceback
+from xos.exceptions import *
+from xos.config import Config
+
+class ConfigurationError(Exception):
+ pass
+
+VCPE_KIND = "vCPE"
+CORD_SUBSCRIBER_KIND = "CordSubscriberRoot"
+
+CORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
+
+# -------------------------------------------
+# VCPE
+# -------------------------------------------
+
+class VSGService(Service):
+ KIND = VCPE_KIND
+
+ URL_FILTER_KIND_CHOICES = ( (None, "None"), ("safebrowsing", "Safe Browsing"), ("answerx", "AnswerX") )
+
+ simple_attributes = ( ("bbs_api_hostname", None),
+ ("bbs_api_port", None),
+ ("bbs_server", None),
+ ("backend_network_label", "hpc_client"),
+ ("dns_servers", "8.8.8.8"),
+ ("url_filter_kind", None),
+ ("node_label", None) )
+
+ def __init__(self, *args, **kwargs):
+ super(VSGService, self).__init__(*args, **kwargs)
+
+ class Meta:
+ app_label = "vsg"
+ verbose_name = "vSG Service"
+ proxy = True
+
+ def allocate_bbs_account(self):
+ vcpes = VSGTenant.get_tenant_objects().all()
+ bbs_accounts = [vcpe.bbs_account for vcpe in vcpes]
+
+ # There's a bit of a race here; some other user could be trying to
+ # allocate a bbs_account at the same time we are.
+
+ for i in range(2,21):
+ account_name = "bbs%02d@onlab.us" % i
+ if (account_name not in bbs_accounts):
+ return account_name
+
+ raise XOSConfigurationError("We've run out of available broadbandshield accounts. Delete some vcpe and try again.")
+
+ @property
+ def bbs_slice(self):
+ bbs_slice_id=self.get_attribute("bbs_slice_id")
+ if not bbs_slice_id:
+ return None
+ bbs_slices=Slice.objects.filter(id=bbs_slice_id)
+ if not bbs_slices:
+ return None
+ return bbs_slices[0]
+
+ @bbs_slice.setter
+ def bbs_slice(self, value):
+ if value:
+ value = value.id
+ self.set_attribute("bbs_slice_id", value)
+
+VSGService.setup_simple_attributes()
+
+class VSGTenant(TenantWithContainer):
+ class Meta:
+ proxy = True
+
+ KIND = VCPE_KIND
+
+ sync_attributes = ("wan_container_ip", "wan_container_mac", "wan_container_netbits",
+ "wan_container_gateway_ip", "wan_container_gateway_mac",
+ "wan_vm_ip", "wan_vm_mac")
+
+ default_attributes = {"instance_id": None,
+ "container_id": None,
+ "users": [],
+ "bbs_account": None,
+ "last_ansible_hash": None,
+ "wan_container_ip": None}
+
+ def __init__(self, *args, **kwargs):
+ super(VSGTenant, self).__init__(*args, **kwargs)
+ self.cached_vrouter=None
+
+ @property
+ def vbng(self):
+ # not supported
+ return None
+
+ @vbng.setter
+ def vbng(self, value):
+ raise XOSConfigurationError("vCPE.vBNG cannot be set this way -- create a new vBNG object and set it's subscriber_tenant instead")
+
+ @property
+ def vrouter(self):
+ vrouter = self.get_newest_subscribed_tenant(VRouterTenant)
+ if not vrouter:
+ return None
+
+ # always return the same object when possible
+ if (self.cached_vrouter) and (self.cached_vrouter.id == vrouter.id):
+ return self.cached_vrouter
+
+ vrouter.caller = self.creator
+ self.cached_vrouter = vrouter
+ return vrouter
+
+ @vrouter.setter
+ def vrouter(self, value):
+ raise XOSConfigurationError("vCPE.vRouter cannot be set this way -- create a new vRuter object and set its subscriber_tenant instead")
+
+ @property
+ def volt(self):
+ from services.volt.models import VOLTTenant
+ if not self.subscriber_tenant:
+ return None
+ volts = VOLTTenant.objects.filter(id=self.subscriber_tenant.id)
+ if not volts:
+ return None
+ return volts[0]
+
+ @property
+ def bbs_account(self):
+ return self.get_attribute("bbs_account", self.default_attributes["bbs_account"])
+
+ @bbs_account.setter
+ def bbs_account(self, value):
+ return self.set_attribute("bbs_account", value)
+
+ @property
+ def last_ansible_hash(self):
+ return self.get_attribute("last_ansible_hash", self.default_attributes["last_ansible_hash"])
+
+ @last_ansible_hash.setter
+ def last_ansible_hash(self, value):
+ return self.set_attribute("last_ansible_hash", value)
+
+ @property
+ def ssh_command(self):
+ if self.instance:
+ return self.instance.get_ssh_command()
+ else:
+ return "no-instance"
+
+ @ssh_command.setter
+ def ssh_command(self, value):
+ pass
+
+ def get_vrouter_field(self, name, default=None):
+ if self.vrouter:
+ return getattr(self.vrouter, name, default)
+ else:
+ return default
+
+ @property
+ def wan_container_ip(self):
+ return self.get_vrouter_field("public_ip", None)
+
+ @property
+ def wan_container_mac(self):
+ return self.get_vrouter_field("public_mac", None)
+
+ @property
+ def wan_container_netbits(self):
+ return self.get_vrouter_field("netbits", None)
+
+ @property
+ def wan_container_gateway_ip(self):
+ return self.get_vrouter_field("gateway_ip", None)
+
+ @property
+ def wan_container_gateway_mac(self):
+ return self.get_vrouter_field("gateway_mac", None)
+
+ @property
+ def wan_vm_ip(self):
+ tags = Tag.select_by_content_object(self.instance).filter(name="vm_vrouter_tenant")
+ if tags:
+ tenant = VRouterTenant.objects.get(id=tags[0].value)
+ return tenant.public_ip
+ else:
+ raise Exception("no vm_vrouter_tenant tag for instance %s" % o.instance)
+
+ @property
+ def wan_vm_mac(self):
+ tags = Tag.select_by_content_object(self.instance).filter(name="vm_vrouter_tenant")
+ if tags:
+ tenant = VRouterTenant.objects.get(id=tags[0].value)
+ return tenant.public_mac
+ else:
+ raise Exception("no vm_vrouter_tenant tag for instance %s" % o.instance)
+
+ @property
+ def is_synced(self):
+ return (self.enacted is not None) and (self.enacted >= self.updated)
+
+ @is_synced.setter
+ def is_synced(self, value):
+ pass
+
+ def get_vrouter_service(self):
+ vrouterServices = VRouterService.get_service_objects().all()
+ if not vrouterServices:
+ raise XOSConfigurationError("No VROUTER Services available")
+ return vrouterServices[0]
+
+ def manage_vrouter(self):
+ # Each vCPE object owns exactly one vRouterTenant object
+
+ if self.deleted:
+ return
+
+ if self.vrouter is None:
+ vrouter = self.get_vrouter_service().get_tenant(address_pool_name="addresses_vsg", subscriber_tenant = self)
+ vrouter.caller = self.creator
+ vrouter.save()
+
+ def cleanup_vrouter(self):
+ if self.vrouter:
+ # print "XXX cleanup vrouter", self.vrouter
+ self.vrouter.delete()
+
+ def cleanup_orphans(self):
+ # ensure vCPE only has one vRouter
+ cur_vrouter = self.vrouter
+ for vrouter in list(self.get_subscribed_tenants(VRouterTenant)):
+ if (not cur_vrouter) or (vrouter.id != cur_vrouter.id):
+ # print "XXX clean up orphaned vrouter", vrouter
+ vrouter.delete()
+
+ if self.orig_instance_id and (self.orig_instance_id != self.get_attribute("instance_id")):
+ instances=Instance.objects.filter(id=self.orig_instance_id)
+ if instances:
+ # print "XXX clean up orphaned instance", instances[0]
+ instances[0].delete()
+
+ def get_slice(self):
+ if not self.provider_service.slices.count():
+ print self, "dio porco"
+ raise XOSConfigurationError("The service has no slices")
+ slice = self.provider_service.slices.all()[0]
+ return slice
+
+ def get_vsg_service(self):
+ return VSGService.get_service_objects().get(id=self.provider_service.id)
+
+ def find_instance_for_s_tag(self, s_tag):
+ #s_tags = STagBlock.objects.find(s_s_tag)
+ #if s_tags:
+ # return s_tags[0].instance
+
+ tags = Tag.objects.filter(name="s_tag", value=s_tag)
+ if tags:
+ return tags[0].content_object
+
+ return None
+
+ def find_or_make_instance_for_s_tag(self, s_tag):
+ instance = self.find_instance_for_s_tag(self.volt.s_tag)
+ if instance:
+ return instance
+
+ flavors = Flavor.objects.filter(name="m1.small")
+ if not flavors:
+ raise XOSConfigurationError("No m1.small flavor")
+
+ slice = self.provider_service.slices.all()[0]
+
+ if slice.default_isolation == "container_vm":
+ (node, parent) = ContainerVmScheduler(slice).pick()
+ else:
+ (node, parent) = LeastLoadedNodeScheduler(slice, label=self.get_vsg_service().node_label).pick()
+
+ instance = Instance(slice = slice,
+ node = node,
+ image = self.image,
+ creator = self.creator,
+ deployment = node.site_deployment.deployment,
+ flavor = flavors[0],
+ isolation = slice.default_isolation,
+ parent = parent)
+
+ self.save_instance(instance)
+
+ return instance
+
+ def manage_container(self):
+ from core.models import Instance, Flavor
+
+ if self.deleted:
+ return
+
+ # For container or container_vm isolation, use what TenantWithCotnainer
+ # provides us
+ slice = self.get_slice()
+ if slice.default_isolation in ["container_vm", "container"]:
+ super(VSGTenant,self).manage_container()
+ return
+
+ if not self.volt:
+ raise XOSConfigurationError("This vCPE container has no volt")
+
+ if self.instance:
+ # We're good.
+ return
+
+ instance = self.find_or_make_instance_for_s_tag(self.volt.s_tag)
+ self.instance = instance
+ super(TenantWithContainer, self).save()
+
+ def cleanup_container(self):
+ if self.get_slice().default_isolation in ["container_vm", "container"]:
+ super(VSGTenant,self).cleanup_container()
+
+ # To-do: cleanup unused instances
+ pass
+
+ def manage_bbs_account(self):
+ if self.deleted:
+ return
+
+ if self.volt and self.volt.subscriber and self.volt.subscriber.url_filter_enable:
+ if not self.bbs_account:
+ # make sure we use the proxied VSGService object, not the generic Service object
+ vcpe_service = VSGService.objects.get(id=self.provider_service.id)
+ self.bbs_account = vcpe_service.allocate_bbs_account()
+ super(VSGTenant, self).save()
+ else:
+ if self.bbs_account:
+ self.bbs_account = None
+ super(VSGTenant, self).save()
+
+ def find_or_make_port(self, instance, network, **kwargs):
+ port = Port.objects.filter(instance=instance, network=network)
+ if port:
+ port = port[0]
+ else:
+ port = Port(instance=instance, network=network, **kwargs)
+ port.save()
+ return port
+
+ def get_lan_network(self, instance):
+ slice = self.provider_service.slices.all()[0]
+ if CORD_USE_VTN:
+ # there should only be one network private network, and its template should not be the management template
+ lan_networks = [x for x in slice.networks.all() if x.template.visibility=="private" and (not "management" in x.template.name)]
+ if len(lan_networks)>1:
+ raise XOSProgrammingError("The vSG slice should only have one non-management private network")
+ else:
+ lan_networks = [x for x in slice.networks.all() if "lan" in x.name]
+ if not lan_networks:
+ raise XOSProgrammingError("No lan_network")
+ return lan_networks[0]
+
+ def save_instance(self, instance):
+ with transaction.atomic():
+ instance.volumes = "/etc/dnsmasq.d,/etc/ufw"
+ super(VSGTenant, self).save_instance(instance)
+
+ if instance.isolation in ["container", "container_vm"]:
+ lan_network = self.get_lan_network(instance)
+ port = self.find_or_make_port(instance, lan_network, ip="192.168.0.1", port_id="unmanaged")
+ port.set_parameter("c_tag", self.volt.c_tag)
+ port.set_parameter("s_tag", self.volt.s_tag)
+ port.set_parameter("device", "eth1")
+ port.set_parameter("bridge", "br-lan")
+
+ wan_networks = [x for x in instance.slice.networks.all() if "wan" in x.name]
+ if not wan_networks:
+ raise XOSProgrammingError("No wan_network")
+ port = self.find_or_make_port(instance, wan_networks[0])
+ port.set_parameter("next_hop", value="10.0.1.253") # FIX ME
+ port.set_parameter("device", "eth0")
+
+ if instance.isolation in ["vm"]:
+ lan_network = self.get_lan_network(instance)
+ port = self.find_or_make_port(instance, lan_network)
+ port.set_parameter("c_tag", self.volt.c_tag)
+ port.set_parameter("s_tag", self.volt.s_tag)
+ port.set_parameter("neutron_port_name", "stag-%s" % self.volt.s_tag)
+ port.save()
+
+ # tag the instance with the s-tag, so we can easily find the
+ # instance later
+ if self.volt and self.volt.s_tag:
+ tags = Tag.objects.filter(name="s_tag", value=self.volt.s_tag)
+ if not tags:
+ tag = Tag(service=self.provider_service, content_object=instance, name="s_tag", value=self.volt.s_tag)
+ tag.save()
+
+ # VTN-CORD needs a WAN address for the VM, so that the VM can
+ # be configured.
+ if CORD_USE_VTN:
+ tags = Tag.select_by_content_object(instance).filter(name="vm_vrouter_tenant")
+ if not tags:
+ vrouter = self.get_vrouter_service().get_tenant(address_pool_name="addresses_vsg", subscriber_service = self.provider_service)
+ vrouter.set_attribute("tenant_for_instance_id", instance.id)
+ vrouter.save()
+ tag = Tag(service=self.provider_service, content_object=instance, name="vm_vrouter_tenant", value="%d" % vrouter.id)
+ tag.save()
+
+ def save(self, *args, **kwargs):
+ if not self.creator:
+ if not getattr(self, "caller", None):
+ # caller must be set when creating a vCPE since it creates a slice
+ raise XOSProgrammingError("VSGTenant's self.caller was not set")
+ self.creator = self.caller
+ if not self.creator:
+ raise XOSProgrammingError("VSGTenant's self.creator was not set")
+
+ super(VSGTenant, self).save(*args, **kwargs)
+ model_policy_vcpe(self.pk)
+
+ def delete(self, *args, **kwargs):
+ self.cleanup_vrouter()
+ self.cleanup_container()
+ super(VSGTenant, self).delete(*args, **kwargs)
+
+def model_policy_vcpe(pk):
+ # TODO: this should be made in to a real model_policy
+ with transaction.atomic():
+ vcpe = VSGTenant.objects.select_for_update().filter(pk=pk)
+ if not vcpe:
+ return
+ vcpe = vcpe[0]
+ vcpe.manage_container()
+ vcpe.manage_vrouter()
+ vcpe.manage_bbs_account()
+ vcpe.cleanup_orphans()
+
+
diff --git a/xos/synchronizers/vcpe/broadbandshield.py b/xos/onboard/vsg/synchronizer/broadbandshield.py
similarity index 100%
rename from xos/synchronizers/vcpe/broadbandshield.py
rename to xos/onboard/vsg/synchronizer/broadbandshield.py
diff --git a/xos/synchronizers/vcpe/files/docker.list b/xos/onboard/vsg/synchronizer/files/docker.list
similarity index 100%
rename from xos/synchronizers/vcpe/files/docker.list
rename to xos/onboard/vsg/synchronizer/files/docker.list
diff --git a/xos/synchronizers/vcpe/files/etc/rc.local b/xos/onboard/vsg/synchronizer/files/etc/rc.local
similarity index 100%
rename from xos/synchronizers/vcpe/files/etc/rc.local
rename to xos/onboard/vsg/synchronizer/files/etc/rc.local
diff --git a/xos/synchronizers/vcpe/files/etc/service/message/run b/xos/onboard/vsg/synchronizer/files/etc/service/message/run
similarity index 100%
rename from xos/synchronizers/vcpe/files/etc/service/message/run
rename to xos/onboard/vsg/synchronizer/files/etc/service/message/run
diff --git a/xos/synchronizers/vcpe/files/etc/ufw/after.init b/xos/onboard/vsg/synchronizer/files/etc/ufw/after.init
similarity index 100%
rename from xos/synchronizers/vcpe/files/etc/ufw/after.init
rename to xos/onboard/vsg/synchronizer/files/etc/ufw/after.init
diff --git a/xos/synchronizers/vcpe/files/etc/ufw/after.rules b/xos/onboard/vsg/synchronizer/files/etc/ufw/after.rules
similarity index 100%
rename from xos/synchronizers/vcpe/files/etc/ufw/after.rules
rename to xos/onboard/vsg/synchronizer/files/etc/ufw/after.rules
diff --git a/xos/synchronizers/vcpe/files/etc/ufw/after6.rules b/xos/onboard/vsg/synchronizer/files/etc/ufw/after6.rules
similarity index 100%
rename from xos/synchronizers/vcpe/files/etc/ufw/after6.rules
rename to xos/onboard/vsg/synchronizer/files/etc/ufw/after6.rules
diff --git a/xos/synchronizers/vcpe/files/etc/ufw/applications.d/openssh-server b/xos/onboard/vsg/synchronizer/files/etc/ufw/applications.d/openssh-server
similarity index 100%
rename from xos/synchronizers/vcpe/files/etc/ufw/applications.d/openssh-server
rename to xos/onboard/vsg/synchronizer/files/etc/ufw/applications.d/openssh-server
diff --git a/xos/synchronizers/vcpe/files/etc/ufw/before.init b/xos/onboard/vsg/synchronizer/files/etc/ufw/before.init
similarity index 100%
rename from xos/synchronizers/vcpe/files/etc/ufw/before.init
rename to xos/onboard/vsg/synchronizer/files/etc/ufw/before.init
diff --git a/xos/synchronizers/vcpe/files/etc/ufw/before6.rules b/xos/onboard/vsg/synchronizer/files/etc/ufw/before6.rules
similarity index 100%
rename from xos/synchronizers/vcpe/files/etc/ufw/before6.rules
rename to xos/onboard/vsg/synchronizer/files/etc/ufw/before6.rules
diff --git a/xos/synchronizers/vcpe/files/etc/ufw/sysctl.conf b/xos/onboard/vsg/synchronizer/files/etc/ufw/sysctl.conf
similarity index 100%
rename from xos/synchronizers/vcpe/files/etc/ufw/sysctl.conf
rename to xos/onboard/vsg/synchronizer/files/etc/ufw/sysctl.conf
diff --git a/xos/synchronizers/vcpe/files/etc/ufw/ufw.conf b/xos/onboard/vsg/synchronizer/files/etc/ufw/ufw.conf
similarity index 100%
rename from xos/synchronizers/vcpe/files/etc/ufw/ufw.conf
rename to xos/onboard/vsg/synchronizer/files/etc/ufw/ufw.conf
diff --git a/xos/synchronizers/vcpe/files/vcpe.conf b/xos/onboard/vsg/synchronizer/files/vcpe.conf
similarity index 100%
rename from xos/synchronizers/vcpe/files/vcpe.conf
rename to xos/onboard/vsg/synchronizer/files/vcpe.conf
diff --git a/xos/synchronizers/vcpe/files/vcpe.dnsmasq b/xos/onboard/vsg/synchronizer/files/vcpe.dnsmasq
similarity index 100%
rename from xos/synchronizers/vcpe/files/vcpe.dnsmasq
rename to xos/onboard/vsg/synchronizer/files/vcpe.dnsmasq
diff --git a/xos/synchronizers/vcpe/files/vm-resolv.conf b/xos/onboard/vsg/synchronizer/files/vm-resolv.conf
similarity index 100%
rename from xos/synchronizers/vcpe/files/vm-resolv.conf
rename to xos/onboard/vsg/synchronizer/files/vm-resolv.conf
diff --git a/xos/onboard/vsg/synchronizer/manifest b/xos/onboard/vsg/synchronizer/manifest
new file mode 100644
index 0000000..d13ee05
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/manifest
@@ -0,0 +1,49 @@
+templates/bwlimit.sh.j2
+templates/vlan_sample.j2
+templates/before.rules.j2
+templates/start-vcpe.sh.j2
+templates/dnsmasq_safe_servers.j2
+templates/firewall_sample.j2
+templates/rc.local.j2
+templates/vcpe.conf.j2
+templates/message.html.j2
+templates/dnsmasq_servers.j2
+templates/start-vcpe-vtn.sh.j2
+manifest
+broadbandshield.py
+observer_ansible_test.py
+vcpe_synchronizer_config
+start-bbs.sh
+steps/sync_vcpetenant.py
+steps/sync_vcpetenant_new.yaml
+steps/sync_vcpetenant_vtn.yaml
+steps/sync_vcpetenant.yaml
+steps/test.yaml
+steps/ansible_test/README
+steps/ansible_test/test.yaml
+steps/ansible_test/xos.py
+steps/ansible_test/test.sh
+steps/ansible_test/inventory.txt
+start.sh
+files/vcpe.conf
+files/etc/service/message/run
+files/etc/rc.local
+files/etc/ufw/after6.rules
+files/etc/ufw/applications.d/openssh-server
+files/etc/ufw/sysctl.conf
+files/etc/ufw/ufw.conf
+files/etc/ufw/before6.rules
+files/etc/ufw/after.init
+files/etc/ufw/before.init
+files/etc/ufw/after.rules
+files/vm-resolv.conf
+files/docker.list
+files/vcpe.dnsmasq
+run-vtn.sh
+stop.sh
+vcpe-synchronizer.py
+model-deps
+supervisor/vcpe-observer.conf
+run.sh
+vtn_vcpe_synchronizer_config
+vcpe_stats_notifier.py
diff --git a/xos/synchronizers/fabric/model-deps b/xos/onboard/vsg/synchronizer/model-deps
similarity index 100%
rename from xos/synchronizers/fabric/model-deps
rename to xos/onboard/vsg/synchronizer/model-deps
diff --git a/xos/synchronizers/vcpe/observer_ansible_test.py b/xos/onboard/vsg/synchronizer/observer_ansible_test.py
similarity index 100%
rename from xos/synchronizers/vcpe/observer_ansible_test.py
rename to xos/onboard/vsg/synchronizer/observer_ansible_test.py
diff --git a/xos/synchronizers/vcpe/run-vtn.sh b/xos/onboard/vsg/synchronizer/run-vtn.sh
similarity index 100%
rename from xos/synchronizers/vcpe/run-vtn.sh
rename to xos/onboard/vsg/synchronizer/run-vtn.sh
diff --git a/xos/synchronizers/vcpe/run.sh b/xos/onboard/vsg/synchronizer/run.sh
similarity index 100%
rename from xos/synchronizers/vcpe/run.sh
rename to xos/onboard/vsg/synchronizer/run.sh
diff --git a/xos/synchronizers/vcpe/start-bbs.sh b/xos/onboard/vsg/synchronizer/start-bbs.sh
similarity index 100%
rename from xos/synchronizers/vcpe/start-bbs.sh
rename to xos/onboard/vsg/synchronizer/start-bbs.sh
diff --git a/xos/synchronizers/vcpe/start.sh b/xos/onboard/vsg/synchronizer/start.sh
similarity index 100%
rename from xos/synchronizers/vcpe/start.sh
rename to xos/onboard/vsg/synchronizer/start.sh
diff --git a/xos/synchronizers/vcpe/steps/ansible_test/README b/xos/onboard/vsg/synchronizer/steps/ansible_test/README
similarity index 100%
rename from xos/synchronizers/vcpe/steps/ansible_test/README
rename to xos/onboard/vsg/synchronizer/steps/ansible_test/README
diff --git a/xos/synchronizers/vcpe/steps/ansible_test/inventory.txt b/xos/onboard/vsg/synchronizer/steps/ansible_test/inventory.txt
similarity index 100%
rename from xos/synchronizers/vcpe/steps/ansible_test/inventory.txt
rename to xos/onboard/vsg/synchronizer/steps/ansible_test/inventory.txt
diff --git a/xos/synchronizers/vcpe/steps/ansible_test/test.sh b/xos/onboard/vsg/synchronizer/steps/ansible_test/test.sh
similarity index 100%
rename from xos/synchronizers/vcpe/steps/ansible_test/test.sh
rename to xos/onboard/vsg/synchronizer/steps/ansible_test/test.sh
diff --git a/xos/synchronizers/vcpe/steps/ansible_test/test.yaml b/xos/onboard/vsg/synchronizer/steps/ansible_test/test.yaml
similarity index 100%
rename from xos/synchronizers/vcpe/steps/ansible_test/test.yaml
rename to xos/onboard/vsg/synchronizer/steps/ansible_test/test.yaml
diff --git a/xos/synchronizers/vcpe/steps/ansible_test/xos.py b/xos/onboard/vsg/synchronizer/steps/ansible_test/xos.py
similarity index 100%
rename from xos/synchronizers/vcpe/steps/ansible_test/xos.py
rename to xos/onboard/vsg/synchronizer/steps/ansible_test/xos.py
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant.py b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant.py
similarity index 97%
rename from xos/synchronizers/vcpe/steps/sync_vcpetenant.py
rename to xos/onboard/vsg/synchronizer/steps/sync_vcpetenant.py
index d8bc525..0b777c7 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
+++ b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant.py
@@ -10,7 +10,7 @@
from synchronizers.base.ansible import run_template_ssh
from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
from core.models import Service, Slice, Tag
-from services.cord.models import VSGService, VSGTenant, VOLTTenant
+from services.vsg.models import VSGService, VSGTenant
from services.hpc.models import HpcService, CDNPrefix
from xos.logger import Logger, logging
@@ -31,7 +31,6 @@
observes=VSGTenant
requested_interval=0
template_name = "sync_vcpetenant.yaml"
- service_key_name = "/opt/xos/synchronizers/vcpe/vcpe_private_key"
def __init__(self, *args, **kwargs):
super(SyncVSGTenant, self).__init__(*args, **kwargs)
@@ -67,7 +66,7 @@
dnsdemux_ip = None
cdn_prefixes = []
- cdn_config_fn = "/opt/xos/synchronizers/vcpe/cdn_config"
+ cdn_config_fn = "/opt/xos/synchronizers/vsg/cdn_config"
if os.path.exists(cdn_config_fn):
# manual CDN configuration
# the first line is the address of dnsredir
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant.yaml
similarity index 83%
rename from xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml
rename to xos/onboard/vsg/synchronizer/steps/sync_vcpetenant.yaml
index 9be0f98..880895e 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml
+++ b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant.yaml
@@ -63,7 +63,7 @@
tasks:
{% if full_setup %}
- name: Docker repository
- copy: src=/opt/xos/synchronizers/vcpe/files/docker.list
+ copy: src=/opt/xos/synchronizers/vsg/files/docker.list
dest=/etc/apt/sources.list.d/docker.list
- name: Import the repository key
@@ -95,7 +95,7 @@
shell: rm -f /etc/resolv.conf
- name: Install resolv.conf
- copy: src=/opt/xos/synchronizers/vcpe/files/vm-resolv.conf
+ copy: src=/opt/xos/synchronizers/vsg/files/vm-resolv.conf
dest=/etc/resolv.conf
- name: Verify if vcpe_stats_notifier ([] is to avoid capturing the shell process) cron job is already running
@@ -110,7 +110,7 @@
# when: cron_job_pids_count.stdout == "0"
- name: Copy cron job to destination
- copy: src=/opt/xos/synchronizers/vcpe/vcpe_stats_notifier.py
+ copy: src=/opt/xos/synchronizers/vsg/vcpe_stats_notifier.py
dest=/usr/local/sbin/vcpe_stats_notifier.py
when: cron_job_pids_count.stdout == "0"
@@ -126,10 +126,10 @@
{% endif %}
- name: vCPE upstart
- template: src=/opt/xos/synchronizers/vcpe/templates/vcpe.conf.j2 dest=/etc/init/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}.conf
+ template: src=/opt/xos/synchronizers/vsg/templates/vcpe.conf.j2 dest=/etc/init/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}.conf
- name: vCPE startup script
- template: src=/opt/xos/synchronizers/vcpe/templates/start-vcpe.sh.j2 dest=/usr/local/sbin/start-vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}.sh mode=0755
+ template: src=/opt/xos/synchronizers/vsg/templates/start-vcpe.sh.j2 dest=/usr/local/sbin/start-vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}.sh mode=0755
notify:
# - restart vcpe
- stop vcpe
@@ -140,22 +140,22 @@
file: path=/etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d state=directory owner=root group=root
- name: vCPE basic dnsmasq config
- copy: src=/opt/xos/synchronizers/vcpe/files/vcpe.dnsmasq dest=/etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d/vcpe.conf owner=root group=root
+ copy: src=/opt/xos/synchronizers/vsg/files/vcpe.dnsmasq dest=/etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d/vcpe.conf owner=root group=root
notify:
- restart dnsmasq
- name: dnsmasq config
- template: src=/opt/xos/synchronizers/vcpe/templates/dnsmasq_servers.j2 dest=/etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d/servers.conf owner=root group=root
+ template: src=/opt/xos/synchronizers/vsg/templates/dnsmasq_servers.j2 dest=/etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d/servers.conf owner=root group=root
notify:
- restart dnsmasq
# These are samples, not necessary for correct function of demo
# - name: networking info
-# template: src=/opt/xos/synchronizers/vcpe/templates/vlan_sample.j2 dest=/etc/vlan_sample owner=root group=root
+# template: src=/opt/xos/synchronizers/vsg/templates/vlan_sample.j2 dest=/etc/vlan_sample owner=root group=root
# - name: firewall info
-# template: src=/opt/xos/synchronizers/vcpe/templates/firewall_sample.j2 dest=/etc/firewall_sample owner=root group=root
+# template: src=/opt/xos/synchronizers/vsg/templates/firewall_sample.j2 dest=/etc/firewall_sample owner=root group=root
- name: Make sure vCPE service is running
service: name=vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} state=started
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant_new.yaml
similarity index 80%
rename from xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml
rename to xos/onboard/vsg/synchronizer/steps/sync_vcpetenant_new.yaml
index 435b721..9c59280 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml
+++ b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant_new.yaml
@@ -74,7 +74,7 @@
when: cron_job_pids_count.stdout == "0"
- name: Copy cron job to destination
- copy: src=/opt/xos/synchronizers/vcpe/vcpe_stats_notifier.py
+ copy: src=/opt/xos/synchronizers/vsg/vcpe_stats_notifier.py
dest=~/bin/vcpe_stats_notifier.py
when: cron_job_pids_count.stdout == "0"
@@ -89,12 +89,12 @@
when: cron_job_pids_count.stdout == "0"
- name: vCPE basic dnsmasq config
- copy: src=/opt/xos/synchronizers/vcpe/files/vcpe.dnsmasq dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/vcpe.conf owner=root group=root
+ copy: src=/opt/xos/synchronizers/vsg/files/vcpe.dnsmasq dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/vcpe.conf owner=root group=root
notify:
- restart dnsmasq
- name: dnsmasq config
- template: src=/opt/xos/synchronizers/vcpe/templates/dnsmasq_servers.j2 dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/servers.conf owner=root group=root
+ template: src=/opt/xos/synchronizers/vsg/templates/dnsmasq_servers.j2 dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/servers.conf owner=root group=root
notify:
- restart dnsmasq
@@ -102,22 +102,22 @@
file: path=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/safe state=directory
- name: dnsmasq "safe" config
- template: src=/opt/xos/synchronizers/vcpe/templates/dnsmasq_safe_servers.j2 dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/safe/servers.conf owner=root group=root
+ template: src=/opt/xos/synchronizers/vsg/templates/dnsmasq_safe_servers.j2 dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/safe/servers.conf owner=root group=root
notify:
- restart dnsmasq
- name: copy base ufw files
- synchronize: src=/opt/xos/synchronizers/vcpe/files/etc/ufw/ dest=/var/container_volumes/{{ container_name }}/etc/ufw/
+ synchronize: src=/opt/xos/synchronizers/vsg/files/etc/ufw/ dest=/var/container_volumes/{{ container_name }}/etc/ufw/
notify:
- reload ufw
- name: redirection rules for safe DNS
- template: src=/opt/xos/synchronizers/vcpe/templates/before.rules.j2 dest=/var/container_volumes/{{ container_name }}/etc/ufw/before.rules owner=root group=root
+ template: src=/opt/xos/synchronizers/vsg/templates/before.rules.j2 dest=/var/container_volumes/{{ container_name }}/etc/ufw/before.rules owner=root group=root
notify:
- reload ufw
- name: base ufw setup uses /etc/rc.local
- copy: src=/opt/xos/synchronizers/vcpe/files/etc/rc.local dest=/var/container_volumes/{{ container_name }}/etc/ owner=root group=root
+ copy: src=/opt/xos/synchronizers/vsg/files/etc/rc.local dest=/var/container_volumes/{{ container_name }}/etc/ owner=root group=root
notify:
- copy in /etc/rc.local
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant_vtn.yaml
similarity index 81%
rename from xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml
rename to xos/onboard/vsg/synchronizer/steps/sync_vcpetenant_vtn.yaml
index b24d15a..0226354 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml
+++ b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant_vtn.yaml
@@ -128,7 +128,7 @@
# when: cron_job_pids_count.stdout == "0"
# - name: Copy cron job to destination
-# copy: src=/opt/xos/synchronizers/vcpe/vcpe_stats_notifier.py
+# copy: src=/opt/xos/synchronizers/vsg/vcpe_stats_notifier.py
# dest=/usr/local/sbin/vcpe_stats_notifier.py
# when: cron_job_pids_count.stdout == "0"
@@ -144,10 +144,10 @@
{% endif %}
- name: vCPE upstart
- template: src=/opt/xos/synchronizers/vcpe/templates/vcpe.conf.j2 dest=/etc/init/{{ container_name }}.conf
+ template: src=/opt/xos/synchronizers/vsg/templates/vcpe.conf.j2 dest=/etc/init/{{ container_name }}.conf
- name: vCPE startup script
- template: src=/opt/xos/synchronizers/vcpe/templates/start-vcpe-vtn.sh.j2 dest=/usr/local/sbin/start-{{ container_name }}.sh mode=0755
+ template: src=/opt/xos/synchronizers/vsg/templates/start-vcpe-vtn.sh.j2 dest=/usr/local/sbin/start-{{ container_name }}.sh mode=0755
notify:
# - restart vcpe
- stop vcpe
@@ -158,17 +158,17 @@
file: path=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/safe state=directory owner=root group=root
- name: vCPE basic dnsmasq config
- copy: src=/opt/xos/synchronizers/vcpe/files/vcpe.dnsmasq dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/vcpe.conf owner=root group=root
+ copy: src=/opt/xos/synchronizers/vsg/files/vcpe.dnsmasq dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/vcpe.conf owner=root group=root
notify:
- restart dnsmasq
- name: dnsmasq config
- template: src=/opt/xos/synchronizers/vcpe/templates/dnsmasq_servers.j2 dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/servers.conf owner=root group=root
+ template: src=/opt/xos/synchronizers/vsg/templates/dnsmasq_servers.j2 dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/servers.conf owner=root group=root
notify:
- restart dnsmasq
- name: dnsmasq "safe" config
- template: src=/opt/xos/synchronizers/vcpe/templates/dnsmasq_safe_servers.j2 dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/safe/servers.conf owner=root group=root
+ template: src=/opt/xos/synchronizers/vsg/templates/dnsmasq_safe_servers.j2 dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/safe/servers.conf owner=root group=root
notify:
- restart dnsmasq
@@ -176,12 +176,12 @@
file: path=/var/container_volumes/{{ container_name }}/mount state=directory owner=root group=root
- name: redirection rules for safe DNS
- template: src=/opt/xos/synchronizers/vcpe/templates/before.rules.j2 dest=/var/container_volumes/{{ container_name }}/mount/before.rules owner=root group=root mode=0644
+ template: src=/opt/xos/synchronizers/vsg/templates/before.rules.j2 dest=/var/container_volumes/{{ container_name }}/mount/before.rules owner=root group=root mode=0644
notify:
- reload ufw
- name: base ufw setup uses /etc/rc.local
- template: src=/opt/xos/synchronizers/vcpe/templates/rc.local.j2 dest=/var/container_volumes/{{ container_name }}/mount/rc.local owner=root group=root mode=0755
+ template: src=/opt/xos/synchronizers/vsg/templates/rc.local.j2 dest=/var/container_volumes/{{ container_name }}/mount/rc.local owner=root group=root mode=0755
notify:
- rerun /etc/rc.local
@@ -189,7 +189,7 @@
file: path=/var/container_volumes/{{ container_name }}/usr/local/sbin state=directory
- name: bandwidth limit script
- template: src=/opt/xos/synchronizers/vcpe/templates/bwlimit.sh.j2 dest=/var/container_volumes/{{ container_name }}/usr/local/sbin/bwlimit.sh owner=root group=root mode=0755
+ template: src=/opt/xos/synchronizers/vsg/templates/bwlimit.sh.j2 dest=/var/container_volumes/{{ container_name }}/usr/local/sbin/bwlimit.sh owner=root group=root mode=0755
notify:
- reset bwlimits
@@ -197,7 +197,7 @@
file: path=/var/container_volumes/{{ container_name }}/etc/service/message state=directory
- name: copy simple webserver
- copy: src=/opt/xos/synchronizers/vcpe/files/etc/service/ dest=/var/container_volumes/{{ container_name }}/etc/service/ owner=root group=root
+ copy: src=/opt/xos/synchronizers/vsg/files/etc/service/ dest=/var/container_volumes/{{ container_name }}/etc/service/ owner=root group=root
when: status != "enabled"
- name: make webserver script executable
@@ -205,7 +205,7 @@
when: status != "enabled"
- name: generate the message page
- template: src=/opt/xos/synchronizers/vcpe/templates/message.html.j2 dest=/var/container_volumes/{{ container_name }}/etc/service/message/message.html owner=root group=root mode=0644
+ template: src=/opt/xos/synchronizers/vsg/templates/message.html.j2 dest=/var/container_volumes/{{ container_name }}/etc/service/message/message.html owner=root group=root mode=0644
when: status != "enabled"
#notify: restart vcpe
diff --git a/xos/synchronizers/vcpe/steps/test.yaml b/xos/onboard/vsg/synchronizer/steps/test.yaml
similarity index 100%
rename from xos/synchronizers/vcpe/steps/test.yaml
rename to xos/onboard/vsg/synchronizer/steps/test.yaml
diff --git a/xos/synchronizers/vcpe/stop.sh b/xos/onboard/vsg/synchronizer/stop.sh
similarity index 100%
rename from xos/synchronizers/vcpe/stop.sh
rename to xos/onboard/vsg/synchronizer/stop.sh
diff --git a/xos/onboard/vsg/synchronizer/supervisor/vcpe-observer.conf b/xos/onboard/vsg/synchronizer/supervisor/vcpe-observer.conf
new file mode 100644
index 0000000..2d90293
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/supervisor/vcpe-observer.conf
@@ -0,0 +1,2 @@
+[program:vcpe-observer]
+command=python /opt/xos/synchronizers/vsg/vcpe-synchronizer.py -C /opt/xos/synchronizers/vsg/vcpe_synchronizer_config
diff --git a/xos/synchronizers/vcpe/templates/before.rules.j2 b/xos/onboard/vsg/synchronizer/templates/before.rules.j2
similarity index 100%
rename from xos/synchronizers/vcpe/templates/before.rules.j2
rename to xos/onboard/vsg/synchronizer/templates/before.rules.j2
diff --git a/xos/synchronizers/vcpe/templates/bwlimit.sh.j2 b/xos/onboard/vsg/synchronizer/templates/bwlimit.sh.j2
similarity index 100%
rename from xos/synchronizers/vcpe/templates/bwlimit.sh.j2
rename to xos/onboard/vsg/synchronizer/templates/bwlimit.sh.j2
diff --git a/xos/synchronizers/vcpe/templates/dnsmasq_safe_servers.j2 b/xos/onboard/vsg/synchronizer/templates/dnsmasq_safe_servers.j2
similarity index 100%
rename from xos/synchronizers/vcpe/templates/dnsmasq_safe_servers.j2
rename to xos/onboard/vsg/synchronizer/templates/dnsmasq_safe_servers.j2
diff --git a/xos/synchronizers/vcpe/templates/dnsmasq_servers.j2 b/xos/onboard/vsg/synchronizer/templates/dnsmasq_servers.j2
similarity index 100%
rename from xos/synchronizers/vcpe/templates/dnsmasq_servers.j2
rename to xos/onboard/vsg/synchronizer/templates/dnsmasq_servers.j2
diff --git a/xos/synchronizers/vcpe/templates/firewall_sample.j2 b/xos/onboard/vsg/synchronizer/templates/firewall_sample.j2
similarity index 100%
rename from xos/synchronizers/vcpe/templates/firewall_sample.j2
rename to xos/onboard/vsg/synchronizer/templates/firewall_sample.j2
diff --git a/xos/synchronizers/vcpe/templates/message.html.j2 b/xos/onboard/vsg/synchronizer/templates/message.html.j2
similarity index 100%
rename from xos/synchronizers/vcpe/templates/message.html.j2
rename to xos/onboard/vsg/synchronizer/templates/message.html.j2
diff --git a/xos/synchronizers/vcpe/templates/rc.local.j2 b/xos/onboard/vsg/synchronizer/templates/rc.local.j2
similarity index 100%
rename from xos/synchronizers/vcpe/templates/rc.local.j2
rename to xos/onboard/vsg/synchronizer/templates/rc.local.j2
diff --git a/xos/synchronizers/vcpe/templates/start-vcpe-vtn.sh.j2 b/xos/onboard/vsg/synchronizer/templates/start-vcpe-vtn.sh.j2
similarity index 100%
rename from xos/synchronizers/vcpe/templates/start-vcpe-vtn.sh.j2
rename to xos/onboard/vsg/synchronizer/templates/start-vcpe-vtn.sh.j2
diff --git a/xos/synchronizers/vcpe/templates/start-vcpe.sh.j2 b/xos/onboard/vsg/synchronizer/templates/start-vcpe.sh.j2
similarity index 100%
rename from xos/synchronizers/vcpe/templates/start-vcpe.sh.j2
rename to xos/onboard/vsg/synchronizer/templates/start-vcpe.sh.j2
diff --git a/xos/synchronizers/vcpe/templates/vcpe.conf.j2 b/xos/onboard/vsg/synchronizer/templates/vcpe.conf.j2
similarity index 100%
rename from xos/synchronizers/vcpe/templates/vcpe.conf.j2
rename to xos/onboard/vsg/synchronizer/templates/vcpe.conf.j2
diff --git a/xos/synchronizers/vcpe/templates/vlan_sample.j2 b/xos/onboard/vsg/synchronizer/templates/vlan_sample.j2
similarity index 100%
rename from xos/synchronizers/vcpe/templates/vlan_sample.j2
rename to xos/onboard/vsg/synchronizer/templates/vlan_sample.j2
diff --git a/xos/synchronizers/vcpe/vcpe-synchronizer.py b/xos/onboard/vsg/synchronizer/vcpe-synchronizer.py
similarity index 100%
rename from xos/synchronizers/vcpe/vcpe-synchronizer.py
rename to xos/onboard/vsg/synchronizer/vcpe-synchronizer.py
diff --git a/xos/synchronizers/vcpe/vcpe_stats_notifier.py b/xos/onboard/vsg/synchronizer/vcpe_stats_notifier.py
similarity index 100%
rename from xos/synchronizers/vcpe/vcpe_stats_notifier.py
rename to xos/onboard/vsg/synchronizer/vcpe_stats_notifier.py
diff --git a/xos/synchronizers/vcpe/vcpe_synchronizer_config b/xos/onboard/vsg/synchronizer/vcpe_synchronizer_config
similarity index 73%
rename from xos/synchronizers/vcpe/vcpe_synchronizer_config
rename to xos/onboard/vsg/synchronizer/vcpe_synchronizer_config
index 110b8e2..e41dc9a 100644
--- a/xos/synchronizers/vcpe/vcpe_synchronizer_config
+++ b/xos/onboard/vsg/synchronizer/vcpe_synchronizer_config
@@ -23,10 +23,10 @@
[observer]
name=vcpe
-dependency_graph=/opt/xos/synchronizers/vcpe/model-deps
-steps_dir=/opt/xos/synchronizers/vcpe/steps
-sys_dir=/opt/xos/synchronizers/vcpe/sys
-deleters_dir=/opt/xos/synchronizers/vcpe/deleters
+dependency_graph=/opt/xos/synchronizers/vsg/model-deps
+steps_dir=/opt/xos/synchronizers/vsg/steps
+sys_dir=/opt/xos/synchronizers/vsg/sys
+deleters_dir=/opt/xos/synchronizers/vsg/deleters
log_file=console
#/var/log/hpc.log
driver=None
diff --git a/xos/synchronizers/vcpe/vtn_vcpe_synchronizer_config b/xos/onboard/vsg/synchronizer/vtn_vcpe_synchronizer_config
similarity index 70%
rename from xos/synchronizers/vcpe/vtn_vcpe_synchronizer_config
rename to xos/onboard/vsg/synchronizer/vtn_vcpe_synchronizer_config
index e92786b..b43d831 100644
--- a/xos/synchronizers/vcpe/vtn_vcpe_synchronizer_config
+++ b/xos/onboard/vsg/synchronizer/vtn_vcpe_synchronizer_config
@@ -23,10 +23,10 @@
[observer]
name=vcpe
-dependency_graph=/opt/xos/synchronizers/vcpe/model-deps
-steps_dir=/opt/xos/synchronizers/vcpe/steps
-sys_dir=/opt/xos/synchronizers/vcpe/sys
-deleters_dir=/opt/xos/synchronizers/vcpe/deleters
+dependency_graph=/opt/xos/synchronizers/vsg/model-deps
+steps_dir=/opt/xos/synchronizers/vsg/steps
+sys_dir=/opt/xos/synchronizers/vsg/sys
+deleters_dir=/opt/xos/synchronizers/vsg/deleters
log_file=console
#/var/log/hpc.log
driver=None
@@ -36,7 +36,7 @@
# set proxy_ssh to false on cloudlab
full_setup=True
proxy_ssh=True
-proxy_ssh_key=/opt/xos/synchronizers/vcpe/node_key
+proxy_ssh_key=/opt/xos/synchronizers/vsg/node_key
proxy_ssh_user=root
[networking]
diff --git a/xos/services/cord/templates/vcpeadmin.html b/xos/onboard/vsg/templates/vcpeadmin.html
similarity index 100%
rename from xos/services/cord/templates/vcpeadmin.html
rename to xos/onboard/vsg/templates/vcpeadmin.html
diff --git a/xos/tosca/resources/vcpeservice.py b/xos/onboard/vsg/tosca/resources/vcpeservice.py
similarity index 91%
rename from xos/tosca/resources/vcpeservice.py
rename to xos/onboard/vsg/tosca/resources/vcpeservice.py
index 972c13c..956d888 100644
--- a/xos/tosca/resources/vcpeservice.py
+++ b/xos/onboard/vsg/tosca/resources/vcpeservice.py
@@ -5,7 +5,7 @@
sys.path.append("/opt/tosca")
from translator.toscalib.tosca_template import ToscaTemplate
-from services.cord.models import VSGService
+from services.vsg.models import VSGService
from service import XOSService
diff --git a/xos/onboard/vsg/vsg-onboard.yaml b/xos/onboard/vsg/vsg-onboard.yaml
new file mode 100644
index 0000000..48f6ad4
--- /dev/null
+++ b/xos/onboard/vsg/vsg-onboard.yaml
@@ -0,0 +1,27 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+ - custom_types/xos.yaml
+
+topology_template:
+ node_templates:
+ servicecontroller#vsg:
+ type: tosca.nodes.ServiceController
+ properties:
+ base_url: file:///opt/xos/onboard/vsg/
+ # The following will concatenate with base_url automatically, if
+ # base_url is non-null.
+ models: models.py
+ admin: admin.py
+ admin_template: templates/vcpeadmin.html
+ synchronizer: synchronizer/manifest
+ synchronizer_run: vcpe-synchronizer.py
+ #tosca_custom_types: exampleservice.yaml
+ tosca_resource: tosca/resources/vcpeservice.py
+ rest_service: subdirectory:vsg api/service/vsg/vsgservice.py
+ rest_tenant: subdirectory:cord api/tenant/cord/vsg.py
+ private_key: file:///opt/xos/key_import/vsg_rsa
+ public_key: file:///opt/xos/key_import/vsg_rsa.pub
+
diff --git a/xos/services/vtn/admin.py b/xos/onboard/vtn/admin.py
similarity index 97%
rename from xos/services/vtn/admin.py
rename to xos/onboard/vtn/admin.py
index bf829c3..71b74e9 100644
--- a/xos/services/vtn/admin.py
+++ b/xos/onboard/vtn/admin.py
@@ -1,6 +1,5 @@
from django.contrib import admin
-from services.cord.models import *
from django import forms
from django.utils.safestring import mark_safe
from django.contrib.auth.admin import UserAdmin
@@ -13,7 +12,6 @@
from core.middleware import get_request
from services.vtn.models import *
-from services.cord.models import CordSubscriberRoot
from functools import update_wrapper
from django.contrib.admin.views.main import ChangeList
diff --git a/xos/api/service/vtn.py b/xos/onboard/vtn/api/service/vtn.py
similarity index 100%
rename from xos/api/service/vtn.py
rename to xos/onboard/vtn/api/service/vtn.py
diff --git a/xos/services/vtn/models.py b/xos/onboard/vtn/models.py
similarity index 96%
rename from xos/services/vtn/models.py
rename to xos/onboard/vtn/models.py
index 52b1633..c805f24 100644
--- a/xos/services/vtn/models.py
+++ b/xos/onboard/vtn/models.py
@@ -8,7 +8,6 @@
from operator import itemgetter, attrgetter, methodcaller
from core.models import Tag
from core.models.service import LeastLoadedNodeScheduler
-from services.cord.models import CordSubscriberRoot
import traceback
from xos.exceptions import *
from xos.config import Config
diff --git a/xos/onboard/vtn/synchronizer/manifest b/xos/onboard/vtn/synchronizer/manifest
new file mode 100644
index 0000000..dccfcdc
--- /dev/null
+++ b/xos/onboard/vtn/synchronizer/manifest
@@ -0,0 +1,10 @@
+manifest
+vtn-synchronizer.py
+steps/sync_tenant.py
+steps/sync_port_addresses.py
+start.sh
+stop.sh
+model-deps
+supervisor/vtn-observer.conf
+run.sh
+vtn_synchronizer_config
diff --git a/xos/synchronizers/fabric/model-deps b/xos/onboard/vtn/synchronizer/model-deps
similarity index 100%
copy from xos/synchronizers/fabric/model-deps
copy to xos/onboard/vtn/synchronizer/model-deps
diff --git a/xos/synchronizers/vtn/run.sh b/xos/onboard/vtn/synchronizer/run.sh
similarity index 100%
rename from xos/synchronizers/vtn/run.sh
rename to xos/onboard/vtn/synchronizer/run.sh
diff --git a/xos/synchronizers/vtn/start.sh b/xos/onboard/vtn/synchronizer/start.sh
similarity index 100%
rename from xos/synchronizers/vtn/start.sh
rename to xos/onboard/vtn/synchronizer/start.sh
diff --git a/xos/synchronizers/vtn/steps/sync_port_addresses.py b/xos/onboard/vtn/synchronizer/steps/sync_port_addresses.py
similarity index 96%
rename from xos/synchronizers/vtn/steps/sync_port_addresses.py
rename to xos/onboard/vtn/synchronizer/steps/sync_port_addresses.py
index d662ff3..bcda05d 100644
--- a/xos/synchronizers/vtn/steps/sync_port_addresses.py
+++ b/xos/onboard/vtn/synchronizer/steps/sync_port_addresses.py
@@ -6,10 +6,9 @@
from django.db.models import F, Q
from xos.config import Config
from synchronizers.base.syncstep import SyncStep
-from core.models import Service, Port, Controller, Tag
+from core.models import Service, Port, Controller, Tag, Tenant
from core.models.service import COARSE_KIND
-from services.cord.models import VSGTenant
-from services.cord.models import Tenant
+from services.vsg.models import VSGTenant
from xos.logger import Logger, logging
from requests.auth import HTTPBasicAuth
diff --git a/xos/synchronizers/vtn/steps/sync_tenant.py b/xos/onboard/vtn/synchronizer/steps/sync_tenant.py
similarity index 97%
rename from xos/synchronizers/vtn/steps/sync_tenant.py
rename to xos/onboard/vtn/synchronizer/steps/sync_tenant.py
index cc374be..a0e6cdb 100644
--- a/xos/synchronizers/vtn/steps/sync_tenant.py
+++ b/xos/onboard/vtn/synchronizer/steps/sync_tenant.py
@@ -6,9 +6,8 @@
from django.db.models import F, Q
from xos.config import Config
from synchronizers.base.syncstep import SyncStep
-from core.models import Service
+from core.models import Service, Tenant
from core.models.service import COARSE_KIND
-from services.cord.models import Tenant
from xos.logger import Logger, logging
from requests.auth import HTTPBasicAuth
diff --git a/xos/synchronizers/vtn/stop.sh b/xos/onboard/vtn/synchronizer/stop.sh
similarity index 100%
rename from xos/synchronizers/vtn/stop.sh
rename to xos/onboard/vtn/synchronizer/stop.sh
diff --git a/xos/synchronizers/vtn/supervisor/vtn-observer.conf b/xos/onboard/vtn/synchronizer/supervisor/vtn-observer.conf
similarity index 100%
rename from xos/synchronizers/vtn/supervisor/vtn-observer.conf
rename to xos/onboard/vtn/synchronizer/supervisor/vtn-observer.conf
diff --git a/xos/synchronizers/vtn/vtn-synchronizer.py b/xos/onboard/vtn/synchronizer/vtn-synchronizer.py
similarity index 100%
rename from xos/synchronizers/vtn/vtn-synchronizer.py
rename to xos/onboard/vtn/synchronizer/vtn-synchronizer.py
diff --git a/xos/synchronizers/vtn/vtn_synchronizer_config b/xos/onboard/vtn/synchronizer/vtn_synchronizer_config
similarity index 100%
rename from xos/synchronizers/vtn/vtn_synchronizer_config
rename to xos/onboard/vtn/synchronizer/vtn_synchronizer_config
diff --git a/xos/services/vtn/templates/vtnadmin.html b/xos/onboard/vtn/templates/vtnadmin.html
similarity index 100%
rename from xos/services/vtn/templates/vtnadmin.html
rename to xos/onboard/vtn/templates/vtnadmin.html
diff --git a/xos/tosca/resources/vtnservice.py b/xos/onboard/vtn/tosca/resources/vtnservice.py
similarity index 100%
rename from xos/tosca/resources/vtnservice.py
rename to xos/onboard/vtn/tosca/resources/vtnservice.py
diff --git a/xos/onboard/vtn/vtn-onboard.yaml b/xos/onboard/vtn/vtn-onboard.yaml
new file mode 100644
index 0000000..460af5a
--- /dev/null
+++ b/xos/onboard/vtn/vtn-onboard.yaml
@@ -0,0 +1,25 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+ - custom_types/xos.yaml
+
+topology_template:
+ node_templates:
+ servicecontroller#vtn:
+ type: tosca.nodes.ServiceController
+ properties:
+ base_url: file:///opt/xos/onboard/vtn/
+ # The following will concatenate with base_url automatically, if
+ # base_url is non-null.
+ models: models.py
+ admin: admin.py
+ admin_template: templates/vtnadmin.html
+ synchronizer: synchronizer/manifest
+ synchronizer_run: vtn-synchronizer.py
+ tosca_resource: tosca/resources/vtnservice.py
+ rest_service: api/service/vtn.py
+ #private_key: file:///opt/xos/key_import/vsg_rsa
+ #public_key: file:///opt/xos/key_import/vsg_rsa.pub
+
diff --git a/xos/services/vtr/admin.py b/xos/onboard/vtr/admin.py
similarity index 98%
rename from xos/services/vtr/admin.py
rename to xos/onboard/vtr/admin.py
index 96074a7..cf5749f 100644
--- a/xos/services/vtr/admin.py
+++ b/xos/onboard/vtr/admin.py
@@ -1,6 +1,5 @@
from django.contrib import admin
-from services.cord.models import *
from django import forms
from django.utils.safestring import mark_safe
from django.contrib.auth.admin import UserAdmin
@@ -13,7 +12,7 @@
from core.middleware import get_request
from services.vtr.models import *
-from services.cord.models import CordSubscriberRoot
+from services.volt.models import CordSubscriberRoot
from functools import update_wrapper
from django.contrib.admin.views.main import ChangeList
diff --git a/xos/api/tenant/truckroll.py b/xos/onboard/vtr/api/tenant/truckroll.py
similarity index 97%
rename from xos/api/tenant/truckroll.py
rename to xos/onboard/vtr/api/tenant/truckroll.py
index b5e9e3f..cc8d62b 100644
--- a/xos/api/tenant/truckroll.py
+++ b/xos/onboard/vtr/api/tenant/truckroll.py
@@ -6,7 +6,6 @@
from rest_framework import status
from core.models import *
from django.forms import widgets
-from services.cord.models import CordSubscriberRoot
from services.vtr.models import VTRTenant, VTRService
from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
diff --git a/xos/services/vtr/models.py b/xos/onboard/vtr/models.py
similarity index 97%
rename from xos/services/vtr/models.py
rename to xos/onboard/vtr/models.py
index 31c26c4..ce2e345 100644
--- a/xos/services/vtr/models.py
+++ b/xos/onboard/vtr/models.py
@@ -8,7 +8,7 @@
from operator import itemgetter, attrgetter, methodcaller
from core.models import Tag
from core.models.service import LeastLoadedNodeScheduler
-from services.cord.models import CordSubscriberRoot
+from services.volt.models import CordSubscriberRoot
import traceback
from xos.exceptions import *
from xos.config import Config
diff --git a/xos/synchronizers/vtr/files/run_tcpdump.sh b/xos/onboard/vtr/synchronizer/files/run_tcpdump.sh
similarity index 100%
rename from xos/synchronizers/vtr/files/run_tcpdump.sh
rename to xos/onboard/vtr/synchronizer/files/run_tcpdump.sh
diff --git a/xos/onboard/vtr/synchronizer/manifest b/xos/onboard/vtr/synchronizer/manifest
new file mode 100644
index 0000000..61ffb39
--- /dev/null
+++ b/xos/onboard/vtr/synchronizer/manifest
@@ -0,0 +1,10 @@
+manifest
+vtr-synchronizer.py
+vtn_vtr_synchronizer_config
+steps/sync_vtrtenant.py
+steps/sync_vtrtenant.yaml
+vtr_synchronizer_config
+files/run_tcpdump.sh
+run-vtn.sh
+model-deps
+run.sh
diff --git a/xos/synchronizers/fabric/model-deps b/xos/onboard/vtr/synchronizer/model-deps
similarity index 100%
copy from xos/synchronizers/fabric/model-deps
copy to xos/onboard/vtr/synchronizer/model-deps
diff --git a/xos/synchronizers/vtr/run-vtn.sh b/xos/onboard/vtr/synchronizer/run-vtn.sh
similarity index 100%
rename from xos/synchronizers/vtr/run-vtn.sh
rename to xos/onboard/vtr/synchronizer/run-vtn.sh
diff --git a/xos/synchronizers/vtr/run.sh b/xos/onboard/vtr/synchronizer/run.sh
similarity index 100%
rename from xos/synchronizers/vtr/run.sh
rename to xos/onboard/vtr/synchronizer/run.sh
diff --git a/xos/synchronizers/vtr/steps/sync_vtrtenant.py b/xos/onboard/vtr/synchronizer/steps/sync_vtrtenant.py
similarity index 87%
rename from xos/synchronizers/vtr/steps/sync_vtrtenant.py
rename to xos/onboard/vtr/synchronizer/steps/sync_vtrtenant.py
index c66f19c..f0f7ef3 100644
--- a/xos/synchronizers/vtr/steps/sync_vtrtenant.py
+++ b/xos/onboard/vtr/synchronizer/steps/sync_vtrtenant.py
@@ -9,7 +9,7 @@
from synchronizers.base.ansible import run_template_ssh
from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
from core.models import Service, Slice, Tag
-from services.cord.models import VSGService, VSGTenant, VOLTTenant, CordSubscriberRoot
+from services.vsg.models import VSGService, VCPE_KIND
from services.vtr.models import VTRService, VTRTenant
from services.hpc.models import HpcService, CDNPrefix
from xos.logger import Logger, logging
@@ -27,7 +27,7 @@
observes=VTRTenant
requested_interval=0
template_name = "sync_vtrtenant.yaml"
- service_key_name = "/opt/xos/synchronizers/vtr/vcpe_private_key"
+ #service_key_name = "/opt/xos/services/vtr/vcpe_private_key"
def __init__(self, *args, **kwargs):
super(SyncVTRTenant, self).__init__(*args, **kwargs)
@@ -66,6 +66,15 @@
else:
return None
+ def get_key_name(self, instance):
+ if instance.slice.service and (instance.slice.service.kind==VCPE_KIND):
+ # We need to use the vsg service's private key. Onboarding won't
+ # by default give us another service's private key, so let's assume
+ # onboarding has been configured to add vsg_rsa to the vtr service.
+ return "/opt/xos/services/vtr/keys/vsg_rsa"
+ else:
+ raise Exception("VTR doesn't know how to get the private key for this instance")
+
def get_extra_attributes(self, o):
vtr_service = self.get_vtr_service(o)
vcpe_service = self.get_vcpe_service(o)
diff --git a/xos/synchronizers/vtr/steps/sync_vtrtenant.yaml b/xos/onboard/vtr/synchronizer/steps/sync_vtrtenant.yaml
similarity index 100%
rename from xos/synchronizers/vtr/steps/sync_vtrtenant.yaml
rename to xos/onboard/vtr/synchronizer/steps/sync_vtrtenant.yaml
diff --git a/xos/synchronizers/vtr/vtn_vtr_synchronizer_config b/xos/onboard/vtr/synchronizer/vtn_vtr_synchronizer_config
similarity index 100%
rename from xos/synchronizers/vtr/vtn_vtr_synchronizer_config
rename to xos/onboard/vtr/synchronizer/vtn_vtr_synchronizer_config
diff --git a/xos/synchronizers/vtr/vtr-synchronizer.py b/xos/onboard/vtr/synchronizer/vtr-synchronizer.py
similarity index 100%
rename from xos/synchronizers/vtr/vtr-synchronizer.py
rename to xos/onboard/vtr/synchronizer/vtr-synchronizer.py
diff --git a/xos/synchronizers/vtr/vtr_synchronizer_config b/xos/onboard/vtr/synchronizer/vtr_synchronizer_config
similarity index 100%
rename from xos/synchronizers/vtr/vtr_synchronizer_config
rename to xos/onboard/vtr/synchronizer/vtr_synchronizer_config
diff --git a/xos/services/vtr/templates/vtradmin.html b/xos/onboard/vtr/templates/vtradmin.html
similarity index 100%
rename from xos/services/vtr/templates/vtradmin.html
rename to xos/onboard/vtr/templates/vtradmin.html
diff --git a/xos/onboard/vtr/vtr-onboard.yaml b/xos/onboard/vtr/vtr-onboard.yaml
new file mode 100644
index 0000000..38dddd1
--- /dev/null
+++ b/xos/onboard/vtr/vtr-onboard.yaml
@@ -0,0 +1,24 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+ - custom_types/xos.yaml
+
+topology_template:
+ node_templates:
+ servicecontroller#vtr:
+ type: tosca.nodes.ServiceController
+ properties:
+ base_url: file:///opt/xos/onboard/vtr/
+ # The following will concatenate with base_url automatically, if
+ # base_url is non-null.
+ models: models.py
+ admin: admin.py
+ admin_template: templates/vtradmin.html
+ synchronizer: synchronizer/manifest
+ synchronizer_run: vtr-synchronizer.py
+ rest_tenant: api/tenant/truckroll.py
+ private_key: file:///opt/xos/key_import/vsg_rsa
+ public_key: file:///opt/xos/key_import/vsg_rsa.pub
+
diff --git a/xos/services/cord/__init__.py b/xos/services/cord_old/__init__.py
similarity index 100%
rename from xos/services/cord/__init__.py
rename to xos/services/cord_old/__init__.py
diff --git a/xos/services/cord/admin.py b/xos/services/cord_old/admin.py
similarity index 100%
rename from xos/services/cord/admin.py
rename to xos/services/cord_old/admin.py
diff --git a/xos/services/cord/migrations/0001_initial.py b/xos/services/cord_old/migrations/0001_initial.py
similarity index 100%
rename from xos/services/cord/migrations/0001_initial.py
rename to xos/services/cord_old/migrations/0001_initial.py
diff --git a/xos/services/cord/migrations/__init__.py b/xos/services/cord_old/migrations/__init__.py
similarity index 100%
rename from xos/services/cord/migrations/__init__.py
rename to xos/services/cord_old/migrations/__init__.py
diff --git a/xos/services/cord/models.py b/xos/services/cord_old/models.py
similarity index 100%
rename from xos/services/cord/models.py
rename to xos/services/cord_old/models.py
diff --git a/xos/services/cord/rest_examples/add_truckroll.sh b/xos/services/cord_old/rest_examples/add_truckroll.sh
similarity index 100%
rename from xos/services/cord/rest_examples/add_truckroll.sh
rename to xos/services/cord_old/rest_examples/add_truckroll.sh
diff --git a/xos/services/cord/rest_examples/add_volt_tenant.sh b/xos/services/cord_old/rest_examples/add_volt_tenant.sh
similarity index 100%
rename from xos/services/cord/rest_examples/add_volt_tenant.sh
rename to xos/services/cord_old/rest_examples/add_volt_tenant.sh
diff --git a/xos/services/cord/rest_examples/config.sh b/xos/services/cord_old/rest_examples/config.sh
similarity index 100%
rename from xos/services/cord/rest_examples/config.sh
rename to xos/services/cord_old/rest_examples/config.sh
diff --git a/xos/services/cord/rest_examples/delete_volt_tenant.sh b/xos/services/cord_old/rest_examples/delete_volt_tenant.sh
similarity index 100%
rename from xos/services/cord/rest_examples/delete_volt_tenant.sh
rename to xos/services/cord_old/rest_examples/delete_volt_tenant.sh
diff --git a/xos/services/cord/rest_examples/list_cord_subscribers.sh b/xos/services/cord_old/rest_examples/list_cord_subscribers.sh
similarity index 100%
rename from xos/services/cord/rest_examples/list_cord_subscribers.sh
rename to xos/services/cord_old/rest_examples/list_cord_subscribers.sh
diff --git a/xos/services/cord/rest_examples/list_truckrolls.sh b/xos/services/cord_old/rest_examples/list_truckrolls.sh
similarity index 100%
rename from xos/services/cord/rest_examples/list_truckrolls.sh
rename to xos/services/cord_old/rest_examples/list_truckrolls.sh
diff --git a/xos/services/cord/rest_examples/list_volt_tenants.sh b/xos/services/cord_old/rest_examples/list_volt_tenants.sh
similarity index 100%
rename from xos/services/cord/rest_examples/list_volt_tenants.sh
rename to xos/services/cord_old/rest_examples/list_volt_tenants.sh
diff --git a/xos/services/cord/templates/vbngadmin.html b/xos/services/cord_old/templates/vbngadmin.html
similarity index 100%
rename from xos/services/cord/templates/vbngadmin.html
rename to xos/services/cord_old/templates/vbngadmin.html
diff --git a/xos/services/vtr/__init__.py b/xos/services/vtr_old/__init__.py
similarity index 100%
rename from xos/services/vtr/__init__.py
rename to xos/services/vtr_old/__init__.py
diff --git a/xos/services/vtr/migrations/0001_initial.py b/xos/services/vtr_old/migrations/0001_initial.py
similarity index 100%
rename from xos/services/vtr/migrations/0001_initial.py
rename to xos/services/vtr_old/migrations/0001_initial.py
diff --git a/xos/services/vtr/migrations/__init__.py b/xos/services/vtr_old/migrations/__init__.py
similarity index 100%
rename from xos/services/vtr/migrations/__init__.py
rename to xos/services/vtr_old/migrations/__init__.py
diff --git a/xos/synchronizers/base/SyncInstanceUsingAnsible.py b/xos/synchronizers/base/SyncInstanceUsingAnsible.py
index 49ca23b..dd7e5c6 100644
--- a/xos/synchronizers/base/SyncInstanceUsingAnsible.py
+++ b/xos/synchronizers/base/SyncInstanceUsingAnsible.py
@@ -82,6 +82,21 @@
def get_node_key(self, node):
return "/root/setup/node_key"
+ def get_key_name(self, instance):
+ if instance.isolation=="vm":
+ if (instance.slice) and (instance.slice.service) and (instance.slice.service.private_key_fn):
+ key_name = instance.slice.service.private_key_fn
+ else:
+ raise Exception("Make sure to set private_key_fn in the service")
+ elif instance.isolation=="container":
+ node = self.get_node(instance)
+ key_name = self.get_node_key(node)
+ else:
+ # container in VM
+ key_name = instance.parent.slice.service.private_key_fn
+
+ return key_name
+
def get_ansible_fields(self, instance):
# return all of the fields that tell Ansible how to talk to the context
# that's setting up the container.
@@ -95,10 +110,7 @@
"username": "ubuntu",
"ssh_ip": instance.get_ssh_ip(),
}
- if (instance.slice) and (instance.slice.service) and (instance.slice.service.private_key_fn):
- key_name = instance.slice.service.private_key_fn
- else:
- raise Exception("Make sure to set private_key_fn in the service")
+
elif (instance.isolation == "container"):
# container on bare metal
node = self.get_node(instance)
@@ -110,7 +122,6 @@
"container_name": "%s-%s" % (instance.slice.name, str(instance.id))
# ssh_ip is not used for container-on-metal
}
- key_name = self.get_node_key(node)
else:
# container in a VM
if not instance.parent:
@@ -128,8 +139,8 @@
"ssh_ip": instance.parent.get_ssh_ip(),
"container_name": "%s-%s" % (instance.slice.name, str(instance.id))
}
- key_name = instance.parent.slice.service.private_key_fn
+ key_name = self.get_key_name(instance)
if not os.path.exists(key_name):
raise Exception("Node key %s does not exist" % key_name)
diff --git a/xos/synchronizers/monitoring_channel/model-deps b/xos/synchronizers/monitoring_channel/model-deps
deleted file mode 100644
index 0967ef4..0000000
--- a/xos/synchronizers/monitoring_channel/model-deps
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/xos/synchronizers/onboarding/xosbuilder.py b/xos/synchronizers/onboarding/xosbuilder.py
index ffb66ee..e7a3e1c 100644
--- a/xos/synchronizers/onboarding/xosbuilder.py
+++ b/xos/synchronizers/onboarding/xosbuilder.py
@@ -14,7 +14,7 @@
logger = Logger(level=logging.INFO)
class XOSBuilder(object):
- UI_KINDS=["models", "admin", "django_library", "rest_service", "rest_tenant", "tosca_custom_types", "tosca_resource","public_key"]
+ UI_KINDS=["models", "admin", "admin_template", "django_library", "rest_service", "rest_tenant", "tosca_custom_types", "tosca_resource","public_key"]
SYNC_CONTROLLER_KINDS=["synchronizer", "private_key", "public_key"]
SYNC_ALLCONTROLLER_KINDS=["models", "django_library"]
@@ -30,15 +30,21 @@
service_name = scr.service_controller.name
base_dirs = {"models": "%s/services/%s/" % (xos_base, service_name),
"admin": "%s/services/%s/" % (xos_base, service_name),
+ "admin_template": "%s/services/%s/templates/" % (xos_base, service_name),
"django_library": "%s/services/%s/" % (xos_base, service_name),
"synchronizer": "%s/synchronizers/%s/" % (xos_base, service_name),
"tosca_custom_types": "%s/tosca/custom_types/" % (xos_base),
"tosca_resource": "%s/tosca/resources/" % (xos_base),
"rest_service": "%s/api/service/" % (xos_base),
"rest_tenant": "%s/api/tenant/" % (xos_base),
- "private_key": "%s/services/%s/keys" % (xos_base, service_name),
+ "private_key": "%s/services/%s/keys/" % (xos_base, service_name),
"public_key": "%s/services/%s/keys/" % (xos_base, service_name)}
- return base_dirs[scr.kind]
+ dest_dir = base_dirs[scr.kind]
+
+ if scr.subdirectory:
+ dest_dir = os.path.join(dest_dir, scr.subdirectory)
+
+ return dest_dir
def get_build_fn(self, scr):
dest_dir = self.get_dest_dir(scr)
@@ -86,33 +92,69 @@
else:
self.download_file(scr.full_url, self.get_download_fn(scr))
- def get_docker_lines(self, scr):
+# XXX docker creates a new container and commits it for every single COPY
+# line in the dockerfile. This causes services with many files (for example,
+# vsg) to take ~ 10-15 minutes to build the docker file. So instead we'll copy
+# the whole build directory, and then run a script that copies the files
+# we want.
+
+# def get_docker_lines(self, scr):
+# if scr.format == "manifest":
+# manifest_fn = self.get_download_fn(scr)
+# manifest = self.read_manifest(scr, manifest_fn)
+# lines = []
+# for (url, download_fn, build_fn) in manifest:
+# script.append("mkdir -p
+# #lines.append("COPY %s /%s" % (build_fn, build_fn))
+# return lines
+# else:
+# build_fn = self.get_build_fn(scr)
+# #return ["COPY %s /%s" % (build_fn, build_fn)]
+
+# def get_controller_docker_lines(self, controller, kinds):
+# need_service_init_py = False
+# dockerfile=[]
+# for scr in controller.service_controller_resources.all():
+# if scr.kind in kinds:
+# lines = self.get_docker_lines(scr)
+# dockerfile = dockerfile + lines
+# if scr.kind in ["admin", "models"]:
+# need_service_init_py = True
+#
+# if need_service_init_py:
+# file(os.path.join(self.build_dir, "opt/xos/empty__init__.py"),"w").write("")
+# dockerfile.append("COPY opt/xos/empty__init__.py /opt/xos/services/%s/__init__.py" % controller.name)
+#
+# return dockerfile
+
+ def get_script_lines(self, scr):
if scr.format == "manifest":
manifest_fn = self.get_download_fn(scr)
manifest = self.read_manifest(scr, manifest_fn)
lines = []
for (url, download_fn, build_fn) in manifest:
- lines.append("ADD %s /%s" % (build_fn, build_fn))
+ lines.append("mkdir -p /%s" % os.path.dirname(build_fn))
+ lines.append("cp /build/%s /%s" % (build_fn, build_fn))
return lines
else:
build_fn = self.get_build_fn(scr)
- return ["ADD %s /%s" % (build_fn, build_fn)]
+ return ["mkdir -p /%s" % os.path.dirname(build_fn),
+ "cp /build/%s /%s" % (build_fn, build_fn)]
- def get_controller_docker_lines(self, controller, kinds):
+ def get_controller_script_lines(self, controller, kinds):
need_service_init_py = False
- dockerfile=[]
+ script=[]
for scr in controller.service_controller_resources.all():
if scr.kind in kinds:
- lines = self.get_docker_lines(scr)
- dockerfile = dockerfile + lines
+ lines = self.get_script_lines(scr)
+ script = script + lines
if scr.kind in ["admin", "models"]:
need_service_init_py = True
if need_service_init_py:
- file(os.path.join(self.build_dir, "opt/xos/empty__init__.py"),"w").write("")
- dockerfile.append("ADD opt/xos/empty__init__.py /opt/xos/services/%s/__init__.py" % controller.name)
+ script.append("echo > /opt/xos/services/%s/__init__.py" % controller.name)
- return dockerfile
+ return script
def check_controller_unready(self, controller):
unready_resources=[]
@@ -124,16 +166,20 @@
# stuff that has to do with building
- def create_xos_app_data(self, name, dockerfile, app_list, migration_list):
+ def create_xos_app_data(self, name, script, app_list, migration_list):
if not os.path.exists(os.path.join(self.build_dir,"opt/xos/xos")):
os.makedirs(os.path.join(self.build_dir,"opt/xos/xos"))
if app_list:
- dockerfile.append("COPY opt/xos/xos/%s_xosbuilder_app_list /opt/xos/xos/xosbuilder_app_list" % name)
+ script.append("mkdir -p /opt/xos/xos")
+ script.append("cp /build/opt/xos/xos/%s_xosbuilder_app_list /opt/xos/xos/xosbuilder_app_list" % name)
+ #dockerfile.append("COPY opt/xos/xos/%s_xosbuilder_app_list /opt/xos/xos/xosbuilder_app_list" % name)
file(os.path.join(self.build_dir, "opt/xos/xos/%s_xosbuilder_app_list") % name, "w").write("\n".join(app_list)+"\n")
if migration_list:
- dockerfile.append("COPY opt/xos/xos/%s_xosbuilder_migration_list /opt/xos/xos/xosbuilder_migration_list" % name)
+ script.append("mkdir -p /opt/xos/xos")
+ script.append("cp /build/opt/xos/xos/%s_xosbuilder_migration_list /opt/xos/xos/xosbuilder_migration_list" % name)
+ #dockerfile.append("COPY opt/xos/xos/%s_xosbuilder_migration_list /opt/xos/xos/xosbuilder_migration_list" % name)
file(os.path.join(self.build_dir, "opt/xos/xos/%s_xosbuilder_migration_list") % name, "w").write("\n".join(migration_list)+"\n")
def create_ui_dockerfile(self):
@@ -143,17 +189,23 @@
migration_list = []
dockerfile = ["FROM %s" % self.source_ui_image]
+ script = []
for controller in ServiceController.objects.all():
if self.check_controller_unready(controller):
logger.warning("Controller %s has unready resources" % str(controller))
continue
- dockerfile = dockerfile + self.get_controller_docker_lines(controller, self.UI_KINDS)
+ #dockerfile = dockerfile + self.get_controller_docker_lines(controller, self.UI_KINDS)
+ script = script + self.get_controller_script_lines(controller, self.UI_KINDS)
if controller.service_controller_resources.filter(kind="models").exists():
app_list.append("services." + controller.name)
migration_list.append(controller.name)
- self.create_xos_app_data("ui", dockerfile, app_list, migration_list)
+ self.create_xos_app_data("ui", script, app_list, migration_list)
+
+ file(os.path.join(self.build_dir, "install-xos.sh"), "w").write("\n".join(script)+"\n")
+ dockerfile.append("COPY . /build/")
+ dockerfile.append("RUN bash /build/install-xos.sh")
file(os.path.join(self.build_dir, dockerfile_fn), "w").write("\n".join(dockerfile)+"\n")
@@ -162,25 +214,32 @@
def create_synchronizer_dockerfile(self, controller):
# bake in the synchronizer from this controller
- sync_lines = self.get_controller_docker_lines(controller, self.SYNC_CONTROLLER_KINDS)
+ sync_lines = self.get_controller_script_lines(controller, self.SYNC_CONTROLLER_KINDS)
if not sync_lines:
return []
dockerfile_fn = "Dockerfile.%s" % controller.name
dockerfile = ["FROM %s" % self.source_sync_image]
+ script = []
# Now bake in models from this controller as well as the others
# It's important to bake all services in, because some services'
# synchronizers may depend on models from another service.
app_list = []
for c in ServiceController.objects.all():
- dockerfile = dockerfile + self.get_controller_docker_lines(c, self.SYNC_ALLCONTROLLER_KINDS)
+ #dockerfile = dockerfile + self.get_controller_docker_lines(c, self.SYNC_ALLCONTROLLER_KINDS)
+ script = script + self.get_controller_script_lines(c, self.SYNC_ALLCONTROLLER_KINDS)
if controller.service_controller_resources.filter(kind="models").exists():
- app_list.append("services." + controller.name)
+ app_list.append("services." + c.name)
- self.create_xos_app_data(controller.name, dockerfile, app_list, None)
+ self.create_xos_app_data(controller.name, script, app_list, None)
- dockerfile = dockerfile + sync_lines
+ script = script + sync_lines
+
+ file(os.path.join(self.build_dir, "install-%s.sh" % controller.name), "w").write("\n".join(script)+"\n")
+ dockerfile.append("COPY . /build/")
+ dockerfile.append("RUN bash /build/install-%s.sh" % controller.name)
+
file(os.path.join(self.build_dir, dockerfile_fn), "w").write("\n".join(dockerfile)+"\n")
return {"dockerfile_fn": dockerfile_fn,
@@ -218,17 +277,24 @@
# "links": ["xos_db"],
# "volumes": volume_list}
- for c in ServiceController.objects.all():
- if self.check_controller_unready(c):
- logger.warning("Controller %s has unready resources" % str(c))
- continue
+ if not xos.frontend_only:
+ for c in ServiceController.objects.all():
+ if self.check_controller_unready(c):
+ logger.warning("Controller %s has unready resources" % str(c))
+ continue
- containers["xos_synchronizer_%s" % c.name] = \
- {"image": "xosproject/xos-synchronizer-%s" % c.name,
- "command": 'bash -c "sleep 120; cd /opt/xos/synchronizers/%s; bash ./run.sh"' % c.name,
- #"external_links": [db_container_name],
- "links": ["xos_db"],
- "volumes": volume_list}
+ if c.service_controller_resources.filter(kind="synchronizer").exists():
+ if c.synchronizer_run and c.synchronizer_config:
+ command = 'bash -c "sleep 120; cd /opt/xos/synchronizers/%s; python ./%s -C %s"' % (c.name, c.synchronizer_run, c.synchronizer_config)
+ else:
+ command = 'bash -c "sleep 120; cd /opt/xos/synchronizers/%s; bash ./run.sh"' % c.name
+
+ containers["xos_synchronizer_%s" % c.name] = \
+ {"image": "xosproject/xos-synchronizer-%s" % c.name,
+ "command": command,
+ #"external_links": [db_container_name],
+ "links": ["xos_db"],
+ "volumes": volume_list}
vars = { "containers": containers }
diff --git a/xos/synchronizers/openstack/steps/sync_container.py b/xos/synchronizers/openstack/steps/sync_container.py
index 84a2c61..41e1305 100644
--- a/xos/synchronizers/openstack/steps/sync_container.py
+++ b/xos/synchronizers/openstack/steps/sync_container.py
@@ -10,7 +10,6 @@
from synchronizers.base.syncstep import SyncStep, DeferredException
from synchronizers.base.ansible import run_template_ssh
from core.models import Service, Slice, Instance
-from services.onos.models import ONOSService, ONOSApp
from xos.logger import Logger, logging
# hpclibrary will be in steps/..
diff --git a/xos/synchronizers/vbng/model-deps b/xos/synchronizers/vbng/model-deps
deleted file mode 100644
index 0967ef4..0000000
--- a/xos/synchronizers/vbng/model-deps
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/xos/synchronizers/vbng/run.sh b/xos/synchronizers/vbng/run.sh
deleted file mode 100755
index de3ed7c..0000000
--- a/xos/synchronizers/vbng/run.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#if [[ ! -e ./vbng-observer.py ]]; then
-# ln -s ../../xos-observer.py vbng-observer.py
-#fi
-
-export XOS_DIR=/opt/xos
-python vbng-synchronizer.py -C $XOS_DIR/synchronizers/vbng/vbng_synchronizer_config
diff --git a/xos/synchronizers/vbng/start.sh b/xos/synchronizers/vbng/start.sh
deleted file mode 100755
index 9553610..0000000
--- a/xos/synchronizers/vbng/start.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#if [[ ! -e ./vbng-observer.py ]]; then
-# ln -s ../../xos-observer.py vbng-observer.py
-#fi
-
-export XOS_DIR=/opt/xos
-nohup python vbng-synchronizer.py -C $XOS_DIR/synchronizers/vbng/vbng_synchronizer_config > /dev/null 2>&1 &
diff --git a/xos/synchronizers/vbng/steps/sync_vbngtenant.py b/xos/synchronizers/vbng/steps/sync_vbngtenant.py
deleted file mode 100644
index 89e7bc0..0000000
--- a/xos/synchronizers/vbng/steps/sync_vbngtenant.py
+++ /dev/null
@@ -1,142 +0,0 @@
-import os
-import requests
-import socket
-import sys
-import base64
-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 core.models import Service
-from services.cord.models import VSGService, VSGTenant, VBNGTenant, VBNGService
-from services.hpc.models import HpcService, CDNPrefix
-from xos.logger import Logger, logging
-
-# VBNG_API = "http://10.0.3.136:8181/onos/virtualbng/privateip/"
-
-# hpclibrary will be in steps/..
-parentdir = os.path.join(os.path.dirname(__file__),"..")
-sys.path.insert(0,parentdir)
-
-logger = Logger(level=logging.INFO)
-
-class SyncVBNGTenant(SyncStep):
- provides=[VSGTenant]
- observes=VSGTenant
- requested_interval=0
-
- def __init__(self, **args):
- SyncStep.__init__(self, **args)
-
- def fetch_pending(self, deleted):
- if (not deleted):
- objs = VBNGTenant.get_tenant_objects().filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
- else:
- objs = VBNGTenant.get_deleted_tenant_objects()
-
- return objs
-
- def defer_sync(self, o, reason):
- logger.info("defer object %s due to %s" % (str(o), reason),extra=o.tologdict())
- raise Exception("defer object %s due to %s" % (str(o), reason))
-
- def get_vbng_service(self, o):
- if not o.provider_service:
- raise Exception("vBNG tenant %s has no provider_service" % str(o.id))
- services = VBNGService.get_service_objects().filter(id = o.provider_service.id)
- if not services:
- raise Exception("vBNG tenant %s is associated with the wrong kind of provider_service" % str(o.id))
- return services[0]
-
- def get_vbng_url(self, o):
- service = self.get_vbng_service(o)
-
- # if the service object specifies a vbng_url, then use it
- if service.vbng_url:
- return service.vbng_url
-
- # otherwise, see if the service has tenancy in ONOS
- for tenant in service.subscribed_tenants.all():
- if tenant.provider_service and tenant.provider_service.kind == "onos":
- onos_service = tenant.provider_service
- if not onos_service.slices.exists():
- raise Exception("vBNG service is linked to an ONOSApp, but the App's Service has no slices")
- onos_slice = onos_service.slices.all()[0]
- if not onos_slice.instances.exists():
- raise Exception("vBNG service is linked to an ONOSApp, but the App's Service's Slice has no instances")
- instance = onos_slice.instances.all()[0]
-
- #onos_app = ONOSApp.objects.filter(id = tenant.id)
- #instance = onos_app.instance
- #if not instance:
- # raise Exception("ONOSApp has no instance")
-
- if not instance.instance_name:
- raise Exception("vBNG service is linked to an ONOSApp, but the App's Service's Slice's first instance is not instantiated")
- ip = instance.get_network_ip("nat")
- if not ip:
- raise Exception("vBNG service is linked to an ONOSApp, but the App's Service's Slice's first instance does not have an ip")
-
- logger.info("Using ip %s from ONOS Instance %s" % (ip, instance),extra=o.tologdict())
-
- return "http://%s:8181/onos/virtualbng/" % ip
-
- raise Exception("vBNG service does not have vbng_url set, and is not linked to an ONOSApp")
-
- def get_private_interface(self, o):
- vcpes = VSGTenant.get_tenant_objects().all()
- vcpes = [x for x in vcpes if (x.vbng is not None) and (x.vbng.id == o.id)]
- if not vcpes:
- raise Exception("No vCPE tenant is associated with vBNG %s" % str(o.id))
- if len(vcpes)>1:
- raise Exception("More than one vCPE tenant is associated with vBNG %s" % str(o.id))
-
- vcpe = vcpes[0]
- instance = vcpe.instance
-
- if not instance:
- raise Exception("No instance associated with vBNG %s" % str(o.id))
-
- if not vcpe.wan_ip:
- self.defer_sync(o, "does not have a WAN IP yet")
-
- if not vcpe.wan_container_mac:
- # this should never happen; container MAC is computed from WAN IP
- self.defer_sync(o, "does not have a WAN container MAC yet")
-
- return (vcpe.wan_ip, vcpe.wan_container_mac, vcpe.instance.node.name)
-
- def sync_record(self, o):
- logger.info("sync'ing VBNGTenant %s" % str(o),extra=o.tologdict())
-
- if not o.routeable_subnet:
- (private_ip, private_mac, private_hostname) = self.get_private_interface(o)
- logger.info("contacting vBNG service to request mapping for private ip %s mac %s host %s" % (private_ip, private_mac, private_hostname) ,extra=o.tologdict())
-
- url = self.get_vbng_url(o) + "privateip/%s/%s/%s" % (private_ip, private_mac, private_hostname)
- logger.info( "vbng url: %s" % url ,extra=o.tologdict())
- r = requests.post(url )
- if (r.status_code != 200):
- raise Exception("Received error from bng service (%d)" % r.status_code)
- logger.info("received public IP %s from private IP %s" % (r.text, private_ip),extra=o.tologdict())
-
- if r.text == "0":
- raise Exception("VBNG service failed to return a routeable_subnet (probably ran out)")
-
- o.routeable_subnet = r.text
- o.mapped_ip = private_ip
- o.mapped_mac = private_mac
- o.mapped_hostname = private_hostname
-
- o.save()
-
- def delete_record(self, o):
- logger.info("deleting VBNGTenant %s" % str(o),extra=o.tologdict())
-
- if o.mapped_ip:
- private_ip = o.mapped_ip
- logger.info("contacting vBNG service to delete private ip %s" % private_ip,extra=o.tologdict())
- r = requests.delete(self.get_vbng_url(o) + "privateip/%s" % private_ip, )
- if (r.status_code != 200):
- raise Exception("Received error from bng service (%d)" % r.status_code)
-
diff --git a/xos/synchronizers/vbng/stop.sh b/xos/synchronizers/vbng/stop.sh
deleted file mode 100755
index d49591e..0000000
--- a/xos/synchronizers/vbng/stop.sh
+++ /dev/null
@@ -1 +0,0 @@
-pkill -9 -f vbng-observer.py
diff --git a/xos/synchronizers/vbng/supervisor/vbng-observer.conf b/xos/synchronizers/vbng/supervisor/vbng-observer.conf
deleted file mode 100644
index a999318..0000000
--- a/xos/synchronizers/vbng/supervisor/vbng-observer.conf
+++ /dev/null
@@ -1,2 +0,0 @@
-[program:vbng-observer]
-command=python /opt/xos/synchronizers/vbng/vbng-synchronizer.py -C /opt/xos/synchronizers/vbng/vbng_synchronizer_config
diff --git a/xos/synchronizers/vbng/vbng-synchronizer.py b/xos/synchronizers/vbng/vbng-synchronizer.py
deleted file mode 100755
index 84bec4f..0000000
--- a/xos/synchronizers/vbng/vbng-synchronizer.py
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/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/vbng/vbng_synchronizer_config b/xos/synchronizers/vbng/vbng_synchronizer_config
deleted file mode 100644
index d613ce3..0000000
--- a/xos/synchronizers/vbng/vbng_synchronizer_config
+++ /dev/null
@@ -1,38 +0,0 @@
-
-[plc]
-name=plc
-deployment=VICCI
-
-[db]
-name=xos
-user=postgres
-password=password
-host=localhost
-port=5432
-
-[api]
-host=128.112.171.237
-port=8000
-ssl_key=None
-ssl_cert=None
-ca_ssl_cert=None
-ratelimit_enabled=0
-omf_enabled=0
-mail_support_address=support@localhost
-nova_enabled=True
-
-[observer]
-name=vbng
-dependency_graph=/opt/xos/synchronizers/vbng/model-deps
-steps_dir=/opt/xos/synchronizers/vbng/steps
-sys_dir=/opt/xos/synchronizers/vbng/sys
-deleters_dir=/opt/xos/synchronizers/vbng/deleters
-log_file=console
-#/var/log/hpc.log
-driver=None
-pretend=False
-backoff_disabled=True
-
-[feefie]
-client_id='vicci_dev_central'
-user_id='pl'
diff --git a/xos/synchronizers/vcpe/model-deps b/xos/synchronizers/vcpe/model-deps
deleted file mode 100644
index 0967ef4..0000000
--- a/xos/synchronizers/vcpe/model-deps
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/xos/synchronizers/vcpe/supervisor/vcpe-observer.conf b/xos/synchronizers/vcpe/supervisor/vcpe-observer.conf
deleted file mode 100644
index 13d797a..0000000
--- a/xos/synchronizers/vcpe/supervisor/vcpe-observer.conf
+++ /dev/null
@@ -1,2 +0,0 @@
-[program:vcpe-observer]
-command=python /opt/xos/synchronizers/vcpe/vcpe-synchronizer.py -C /opt/xos/synchronizers/vcpe/vcpe_synchronizer_config
diff --git a/xos/synchronizers/vtn/model-deps b/xos/synchronizers/vtn/model-deps
deleted file mode 100644
index 0967ef4..0000000
--- a/xos/synchronizers/vtn/model-deps
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/xos/tests/api/helpers/before_test.py b/xos/tests/api/helpers/before_test.py
index d45f4e5..a977564 100644
--- a/xos/tests/api/helpers/before_test.py
+++ b/xos/tests/api/helpers/before_test.py
@@ -9,7 +9,8 @@
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
import django
from core.models import *
-from services.cord.models import *
+from services.volt.models import *
+from services.vsg.models import *
from services.vtr.models import *
import urllib2
import json
diff --git a/xos/tests/api/helpers/flavors.py b/xos/tests/api/helpers/flavors.py
index e16d41f..dca4d77 100644
--- a/xos/tests/api/helpers/flavors.py
+++ b/xos/tests/api/helpers/flavors.py
@@ -9,8 +9,6 @@
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
import django
from core.models import *
-from services.cord.models import *
-from services.vtr.models import *
import urllib2
import json
django.setup()
diff --git a/xos/tests/api/helpers/subscriber.py b/xos/tests/api/helpers/subscriber.py
index 4ede030..320c73c 100644
--- a/xos/tests/api/helpers/subscriber.py
+++ b/xos/tests/api/helpers/subscriber.py
@@ -9,7 +9,8 @@
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
import django
from core.models import *
-from services.cord.models import *
+from services.volt.models import *
+from services.vsg.models import *
from services.vtr.models import *
from django.contrib.auth import authenticate, login
from django.core.exceptions import PermissionDenied
diff --git a/xos/tests/api/hooks.py b/xos/tests/api/hooks.py
index 43756c9..9fbf83f 100644
--- a/xos/tests/api/hooks.py
+++ b/xos/tests/api/hooks.py
@@ -9,7 +9,8 @@
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
import django
from core.models import *
-from services.cord.models import *
+from services.volt.models import *
+from services.vsg.models import *
from services.vtr.models import *
import urllib2
import json
diff --git a/xos/tools/cleanup_unique.py b/xos/tools/cleanup_unique.py
index 4df82f4..97710ec 100644
--- a/xos/tools/cleanup_unique.py
+++ b/xos/tools/cleanup_unique.py
@@ -4,8 +4,6 @@
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
import django
from core.models import *
-from services.hpc.models import *
-from services.cord.models import *
django.setup()
for obj in ControllerNetwork.deleted_objects.all():
diff --git a/xos/tools/dmdot b/xos/tools/dmdot
index a57c0b1..9cde0ed 100755
--- a/xos/tools/dmdot
+++ b/xos/tools/dmdot
@@ -20,7 +20,7 @@
sys.exit(-1)
# defaults
-apps = ["core", "services.hpc", "services.cord", "services.requestrouter", "services.onos"]
+apps = ["core", "services.hpc", "services.requestrouter", "services.onos"]
output = "-json"
# syntax: dmdot [-json | -dot] [app_name]
diff --git a/xos/tools/purge.py b/xos/tools/purge.py
index 023c2fe..8c081e6 100644
--- a/xos/tools/purge.py
+++ b/xos/tools/purge.py
@@ -4,8 +4,6 @@
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
import django
from core.models import *
-from services.hpc.models import *
-from services.cord.models import *
django.setup()
def purge(cls):
diff --git a/xos/tools/wait_for_object_creation.py b/xos/tools/wait_for_object_creation.py
index 354a213..b2af38f 100755
--- a/xos/tools/wait_for_object_creation.py
+++ b/xos/tools/wait_for_object_creation.py
@@ -5,7 +5,8 @@
import django
from core.models import *
from services.hpc.models import *
-from services.cord.models import *
+from services.volt.models import *
+from services.vsg.models import *
import time
django.setup()
diff --git a/xos/tools/xos-manage b/xos/tools/xos-manage
index 33b0f1a..3478da3 100755
--- a/xos/tools/xos-manage
+++ b/xos/tools/xos-manage
@@ -142,15 +142,14 @@
python ./manage.py makemigrations hpc
python ./manage.py makemigrations requestrouter
python ./manage.py makemigrations syndicate_storage
- python ./manage.py makemigrations cord
python ./manage.py makemigrations mcord
- python ./manage.py makemigrations ceilometer
- python ./manage.py makemigrations onos
+# python ./manage.py makemigrations ceilometer
+# python ./manage.py makemigrations onos
python ./manage.py makemigrations openvpn
- python ./manage.py makemigrations vtr
- python ./manage.py makemigrations vrouter
- python ./manage.py makemigrations vtn
- python ./manage.py makemigrations fabric
+# python ./manage.py makemigrations vtr
+# python ./manage.py makemigrations vrouter
+# python ./manage.py makemigrations vtn
+# python ./manage.py makemigrations fabric
#python ./manage.py makemigrations servcomp
if [[ -e /opt/xos/xos/xosbuilder_migration_list ]]; then
diff --git a/xos/tosca/custom_types/xos.m4 b/xos/tosca/custom_types/xos.m4
index 9e6cb41..ef852af 100644
--- a/xos/tosca/custom_types/xos.m4
+++ b/xos/tosca/custom_types/xos.m4
@@ -27,6 +27,10 @@
type: boolean
required: false
description: True if XOS build should be enabled
+ frontend_only:
+ type: boolean
+ required: false
+ description: True if XOS should not start synchronizer containers
tosca.nodes.XOSVolume:
@@ -72,10 +76,22 @@
type: string
required: false
description: url of admin.py
+ admin_template:
+ type: string
+ required: false
+ description: url of admin html template
synchronizer:
type: string
required: false
description: url of synchronizer manifest
+ synchronizer_run:
+ type: string
+ required: false
+ description: synchronizer run command
+ synchronizer_config:
+ type: string
+ required: false
+ description: synchronizer config filename
tosca_custom_types:
type: string
required: false
diff --git a/xos/tosca/custom_types/xos.yaml b/xos/tosca/custom_types/xos.yaml
index 0888c53..93dad18 100644
--- a/xos/tosca/custom_types/xos.yaml
+++ b/xos/tosca/custom_types/xos.yaml
@@ -57,6 +57,10 @@
type: boolean
required: false
description: True if XOS build should be enabled
+ frontend_only:
+ type: boolean
+ required: false
+ description: True if XOS should not start synchronizer containers
tosca.nodes.XOSVolume:
@@ -180,10 +184,22 @@
type: string
required: false
description: url of admin.py
+ admin_template:
+ type: string
+ required: false
+ description: url of admin html template
synchronizer:
type: string
required: false
description: url of synchronizer manifest
+ synchronizer_run:
+ type: string
+ required: false
+ description: synchronizer run command
+ synchronizer_config:
+ type: string
+ required: false
+ description: synchronizer config filename
tosca_custom_types:
type: string
required: false
diff --git a/xos/tosca/resources/network.py b/xos/tosca/resources/network.py
index fc143d0..8672b76 100644
--- a/xos/tosca/resources/network.py
+++ b/xos/tosca/resources/network.py
@@ -72,8 +72,8 @@
if existing_tenancy:
self.info("Tenancy relationship from %s to %s already exists" % (str(obj), str(provider_service)))
else:
- from services.vrouter.models import VROUTER_KIND, VRouterService
- if provider_service.kind == VROUTER_KIND:
+ if provider_service.kind == "vROUTER":
+ from services.vrouter.models import VRouterService
tenancy = VRouterService.objects.get(id=provider_service.id).get_tenant(address_pool_name="addresses_"+obj.name, subscriber_network=obj)
tenancy.save()
obj.subnet = tenancy.cidr
diff --git a/xos/tosca/resources/servicecontroller.py b/xos/tosca/resources/servicecontroller.py
index d821b56..d7e894a 100644
--- a/xos/tosca/resources/servicecontroller.py
+++ b/xos/tosca/resources/servicecontroller.py
@@ -12,34 +12,51 @@
class XOSServiceController(XOSResource):
provides = "tosca.nodes.ServiceController"
xos_model = ServiceController
- copyin_props = ["base_url"]
+ copyin_props = ["base_url", "synchronizer_run", "synchronizer_config"]
def postprocess_resource_prop(self, obj, kind, format):
values = self.get_property(kind)
if values:
for i,value in enumerate(values.split(",")):
value = value.strip()
+ subdirectory = None
name=kind
if i>0:
name = "%s_%d" %( name, i)
+ if (" " in value):
+ parts=value.split()
+ for part in parts[:-1]:
+ if ":" in part:
+ (lhs, rhs) = part.split(":", 1)
+ if lhs=="subdirectory":
+ subdirectory=rhs
+ else:
+ raise Exception("Malformed value %s" % value)
+ else:
+ raise Exception("Malformed value %s" % value)
+ value = parts[-1]
+
+
scr = ServiceControllerResource.objects.filter(service_controller=obj, name=name, kind=kind, format=format)
if scr:
scr=scr[0]
- if scr.url != value:
+ if (scr.url != value) or (scr.subdirectory!=subdirectory):
self.info("updating resource %s" % kind)
scr.url = value
+ scr.subdirectory = subdirectory
scr.save()
else:
self.info("adding resource %s" % kind)
- scr = ServiceControllerResource(service_controller=obj, name=name, kind=kind, format=format, url=value)
+ scr = ServiceControllerResource(service_controller=obj, name=name, kind=kind, format=format, url=value, subdirectory=subdirectory)
scr.save()
def postprocess(self, obj):
# allow these common resource to be specified directly by the ServiceController tosca object
self.postprocess_resource_prop(obj, "models", "python")
self.postprocess_resource_prop(obj, "admin", "python")
+ self.postprocess_resource_prop(obj, "admin_template", "raw")
self.postprocess_resource_prop(obj, "tosca_custom_types", "yaml")
self.postprocess_resource_prop(obj, "tosca_resource", "python")
self.postprocess_resource_prop(obj, "synchronizer", "manifest")
diff --git a/xos/tosca/resources/vbngservice.py b/xos/tosca/resources/vbngservice.py
deleted file mode 100644
index 28d4a1d..0000000
--- a/xos/tosca/resources/vbngservice.py
+++ /dev/null
@@ -1,16 +0,0 @@
-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 VBNGService
-
-from service import XOSService
-
-class XOSVBGNService(XOSService):
- provides = "tosca.nodes.VBNGService"
- xos_model = VBNGService
- copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "versionNumber", "vbng_url"]
-
diff --git a/xos/tosca/resources/xosmodel.py b/xos/tosca/resources/xosmodel.py
index 188bb4f..b397686 100644
--- a/xos/tosca/resources/xosmodel.py
+++ b/xos/tosca/resources/xosmodel.py
@@ -12,7 +12,7 @@
class XOSXOS(XOSResource):
provides = "tosca.nodes.XOS"
xos_model = XOS
- copyin_props = ["ui_port", "bootstrap_ui_port", "docker_project_name", "enable_build"]
+ copyin_props = ["ui_port", "bootstrap_ui_port", "docker_project_name", "enable_build", "frontend_only"]
class XOSVolume(XOSResource):
provides = "tosca.nodes.XOSVolume"
diff --git a/xos/xos/settings.py b/xos/xos/settings.py
index c0135be..53d9c2c 100644
--- a/xos/xos/settings.py
+++ b/xos/xos/settings.py
@@ -182,17 +182,16 @@
'django_extensions',
'core',
'services.hpc',
- 'services.cord',
'services.mcord',
- 'services.onos',
- 'services.ceilometer',
+# 'services.onos',
+# 'services.ceilometer',
'services.requestrouter',
'services.syndicate_storage',
'services.openvpn',
- 'services.vtr',
- 'services.vrouter',
- 'services.vtn',
- 'services.fabric',
+# 'services.vtr',
+# 'services.vrouter',
+# 'services.vtn',
+# 'services.fabric',
'geoposition',
'rest_framework_swagger',
)