Merge branch 'master' into feature/volt-autoconfig
diff --git a/views/ngXosLib/README.md b/views/ngXosLib/README.md
index f4b9c8f..b19cd1f 100644
--- a/views/ngXosLib/README.md
+++ b/views/ngXosLib/README.md
@@ -39,6 +39,9 @@
To develop components inside this folder there is a particular command: `npm run dev`, this will watch the helpers file and rebuild them with sourcemaps. For this reason remember to build them when done developing.
+>While developing components in this library you should execute the test. The `npm test` command will run Jasmine test for the whole complete library.
+>If you want to specify a single test file to be execute, you can add it to the command like: `npm test smart-pie`, the tool will now read only the test specified in the `smart-pie.test.js` file.
+
When some changes are applied to this common library it should be rebuilt with: `npm run build`
To generate the relative documentation use: `npm run doc`
diff --git a/views/ngXosLib/karma.conf.js b/views/ngXosLib/karma.conf.js
index 36ddda1..ed2ec3e 100644
--- a/views/ngXosLib/karma.conf.js
+++ b/views/ngXosLib/karma.conf.js
@@ -3,6 +3,12 @@
/* eslint indent: [2,2], quotes: [2, "single"]*/
+// this is to load a different suite of test while developing
+var testFiles = '*';
+if(process.argv[4]){
+ testFiles = process.argv[4];
+}
+
/*eslint-disable*/
var wiredep = require('wiredep');
var path = require('path');
@@ -15,7 +21,7 @@
'node_modules/babel-polyfill/dist/polyfill.js',
'xosHelpers/src/**/*.module.js',
'xosHelpers/src/**/*.js',
- 'xosHelpers/spec/**/*.test.js'
+ `xosHelpers/spec/**/${testFiles}.test.js`
// 'xosHelpers/spec/ui/smart-pie.test.js'
]);
@@ -89,7 +95,7 @@
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: [
'PhantomJS',
- 'Chrome'
+ // 'Chrome'
],
diff --git a/views/ngXosLib/package.json b/views/ngXosLib/package.json
index c4f902d..e0fa151 100644
--- a/views/ngXosLib/package.json
+++ b/views/ngXosLib/package.json
@@ -4,7 +4,7 @@
"description": "Angular Version of XosLib, containing Helpers and ngResources",
"main": "index.js",
"scripts": {
- "test": "karma start",
+ "test": "karma start karma.conf.js",
"test:ci": "karma start karma.conf.ci.js",
"apigen": "node apigen/blueprintToNgResource.js",
"swagger": "node xos-swagger-def.js",
diff --git a/views/ngXosLib/xosHelpers/spec/ui/smart-pie.test.js b/views/ngXosLib/xosHelpers/spec/ui/smart-pie.test.js
index 8dce4f9..4c90421 100644
--- a/views/ngXosLib/xosHelpers/spec/ui/smart-pie.test.js
+++ b/views/ngXosLib/xosHelpers/spec/ui/smart-pie.test.js
@@ -7,16 +7,37 @@
(function () {
'use strict';
- let mockData;
+ let mockData, compile, rootScope, spy, scope, isolatedScope, element, interval;
+
+ const compileElement = () => {
+
+ if(!scope){
+ scope = rootScope.$new();
+ }
+
+ element = angular.element('<xos-smart-pie config="config"></xos-smart-pie>');
+ compile(element)(scope);
+ scope.$digest();
+ isolatedScope = element.isolateScope().vm;
+ }
describe('The xos.helper module', function(){
describe('The xos-smart-pie component', () => {
- var spy, scope, isolatedScope, element;
beforeEach(module('xos.helpers'));
- beforeEach(function() {
+ beforeEach(function(){
+ module(function($provide){
+ $provide.service('MockResource', function(){
+ return {
+ query: ''
+ }
+ });
+ });
+ });
+
+ beforeEach(inject(function ($compile, $rootScope) {
// set mockData
mockData = [
@@ -40,95 +61,151 @@
}
]
- });
-
- // mock the service
- beforeEach(function(){
- module(function($provide){
- $provide.service('MockResource', function(){
- return {
- query: ''
- }
- });
- });
- })
-
- beforeEach(inject(function ($compile, $rootScope, $q, MockResource) {
- scope = $rootScope.$new();
-
- scope.config = {
- resource: 'MockResource',
- groupBy: 'category',
- classes: 'my-test-class'
- };
-
- spy = MockResource;
-
- spyOn(MockResource, 'query').and.callFake(function() {
- var deferred = $q.defer();
- deferred.resolve(mockData);
- return {$promise: deferred.promise};
- });
-
- element = angular.element('<xos-smart-pie config="config"></xos-smart-pie>');
- $compile(element)(scope);
- scope.$digest();
- isolatedScope = element.isolateScope().vm;
+ compile = $compile;
+ rootScope = $rootScope;
}));
- it('should attach provided classes', () => {
- expect($(element).find('canvas')).toHaveClass('my-test-class');
- });
-
- it('should group elements', () => {
- let groupedData = [2, 1];
- expect(spy.query).toHaveBeenCalled();
- expect(isolatedScope.data).toEqual(groupedData);
- });
-
- describe('when a labelFormatter function is provided', () => {
- beforeEach(inject(function ($compile, $rootScope){
+ it('should throw an error if no resource and no data are passed in the config', inject(($compile, $rootScope) => {
+ function errorFunctionWrapper(){
+ // setup the parent scope
scope = $rootScope.$new();
+ scope.config = {};
+ compileElement();
+ }
+ expect(errorFunctionWrapper).toThrow(new Error('[xosSmartPie] Please provide a resource or an array of data in the configuration'));
+ }));
+
+ describe('when data are passed in the configuration', () => {
+ beforeEach(inject(function ($compile, $rootScope) {
+ scope = $rootScope.$new();
+
scope.config = {
- resource: 'MockResource',
+ data: mockData,
groupBy: 'category',
- classes: 'label-formatter-test',
- labelFormatter: (labels) => {
+ classes: 'my-test-class'
+ };
+
+ compileElement();
+ }));
+
+
+ it('should attach provided classes', () => {
+ expect($(element).find('canvas')).toHaveClass('my-test-class');
+ });
+
+ it('should group elements', () => {
+ let groupedData = [2, 1];
+ expect(isolatedScope.data).toEqual(groupedData);
+ });
+
+ describe('when a labelFormatter function is provided', () => {
+ beforeEach(() => {
+ scope.config.labelFormatter = (labels) => {
return labels.map(l => l === '1' ? 'First' : 'Second');
- }
- };
- element = angular.element('<xos-smart-pie config="config"></xos-smart-pie>');
- $compile(element)(scope);
- scope.$digest();
- isolatedScope = element.isolateScope().vm;
- }));
+ };
+ compileElement();
+ });
+ it('should format labels', () => {
+ expect(isolatedScope.labels).toEqual(['First', 'Second'])
+ });
+ });
- it('should format labels', () => {
- expect(isolatedScope.labels).toEqual(['First', 'Second'])
+ describe('when provided data changes', () => {
+ beforeEach(() => {
+ scope.config.data.push({
+ id: 2,
+ first_name: 'Danaerys',
+ last_name: 'Targaryen',
+ category: 1
+ });
+ scope.$digest();
+ });
+ it('should calculate again the data', () => {
+ expect(isolatedScope.data).toEqual([3, 1]);
+ });
});
});
- describe('when polling is enabled', () => {
- beforeEach(inject(function ($compile, $rootScope){
+
+ describe('when a resource is specified in the configuration', () => {
+
+ beforeEach(inject(function ($compile, $rootScope, $q, MockResource) {
scope = $rootScope.$new();
+
scope.config = {
resource: 'MockResource',
groupBy: 'category',
- classes: 'label-formatter-test',
- poll: 2
+ classes: 'my-test-class'
};
- element = angular.element('<xos-smart-pie config="config"></xos-smart-pie>');
- $compile(element)(scope);
- scope.$digest();
- isolatedScope = element.isolateScope().vm;
+
+ spy = MockResource;
+
+ spyOn(MockResource, 'query').and.callFake(function() {
+ var deferred = $q.defer();
+ deferred.resolve(mockData);
+ return {$promise: deferred.promise};
+ });
+
+ compileElement();
}));
- it('should call the backend every 2 second', () => {
+
+ it('should call the server and group elements', () => {
+ let groupedData = [2, 1];
expect(spy.query).toHaveBeenCalled();
- // $interval
+ expect(isolatedScope.data).toEqual(groupedData);
+ });
+
+ describe('when a labelFormatter function is provided', () => {
+ beforeEach(inject(function ($compile, $rootScope){
+ scope = $rootScope.$new();
+ scope.config = {
+ resource: 'MockResource',
+ groupBy: 'category',
+ classes: 'label-formatter-test',
+ labelFormatter: (labels) => {
+ return labels.map(l => l === '1' ? 'First' : 'Second');
+ }
+ };
+ compileElement();
+ }));
+
+ it('should format labels', () => {
+ expect(isolatedScope.labels).toEqual(['First', 'Second'])
+ });
+ });
+
+ describe('when polling is enabled', () => {
+ beforeEach(inject(function ($compile, $rootScope, $interval){
+
+ //mocked $interval (by ngMock)
+ interval = $interval;
+
+ // cleaning the spy
+ spy.query.calls.reset()
+
+ scope = $rootScope.$new();
+ scope.config = {
+ resource: 'MockResource',
+ groupBy: 'category',
+ classes: 'label-formatter-test',
+ poll: 2
+ };
+ compileElement();
+ }));
+
+ it('should call the backend every 2 second', () => {
+ expect(spy.query).toHaveBeenCalled();
+ expect(spy.query.calls.count()).toEqual(1);
+ interval.flush(2000);
+ expect(spy.query.calls.count()).toEqual(2);
+ interval.flush(2000);
+ expect(spy.query.calls.count()).toEqual(3)
+ });
});
});
+
});
});
})();
\ 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 7279995..a6d85c8 100644
--- a/views/ngXosLib/xosHelpers/spec/ui/table.test.js
+++ b/views/ngXosLib/xosHelpers/spec/ui/table.test.js
@@ -94,7 +94,6 @@
xdescribe('when a field type is provided', () => {
describe('and is boolean', () => {
beforeEach(() => {
- console.log('iS: ' + isolatedScope);
isolatedScope.config = {
columns: [
{
@@ -118,7 +117,6 @@
it('should render an incon', () => {
let td1 = $(element).find('tbody tr:first-child td')[0];
let td2 = $(element).find('tbody tr:last-child td')[0];
- console.log(td2);
expect($(td1).find('i')).toHaveClass('glyphicon-ok');
expect($(td2).find('i')).toHaveClass('glyphicon-remove');
});
@@ -126,7 +124,6 @@
describe('and is date', () => {
beforeEach(() => {
- console.log('iS: ' + isolatedScope);
isolatedScope.config = {
columns: [
{
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartPie/smartPie.component.js b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartPie/smartPie.component.js
index 2290583..6616b50 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartPie/smartPie.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartPie/smartPie.component.js
@@ -32,14 +32,97 @@
* ```
* @scope
* @example
- <example module="sampleSmartPie">
+
+ Displaying Local data
+
+ <example module="sampleSmartPieLocal">
+ <file name="index.html">
+ <div ng-controller="SampleCtrlLocal as vm">
+ <xos-smart-pie config="vm.configLocal"></xos-smart-pie>
+ </div>
+ </file>
+ <file name="script.js">
+ angular.module('sampleSmartPieLocal', ['xos.uiComponents'])
+ .factory('_', function($window){
+ return $window._;
+ })
+ .controller('SampleCtrlLocal', function($timeout){
+
+ this.datas = [
+ {id: 1, first_name: 'Jon', last_name: 'aaa', category: 2},
+ {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 1},
+ {id: 3, first_name: 'Aria', last_name: 'Stark', category: 2}
+ ];
+
+ this.configLocal = {
+ data: [],
+ groupBy: 'category',
+ classes: 'local',
+ labelFormatter: (labels) => {
+ return labels.map(l => l === '1' ? 'North' : 'Dragon');
+ }
+ };
+
+ $timeout(() => {
+ // this need to be triggered in this way just because of ngDoc,
+ // otherwise you can assign data directly in the config
+ this.configLocal.data = this.datas;
+ }, 1)
+ });
+ </file>
+ </example>
+
+ Fetching data from API
+
+ <example module="sampleSmartPieResource">
<file name="index.html">
<div ng-controller="SampleCtrl as vm">
<xos-smart-pie config="vm.config"></xos-smart-pie>
</div>
</file>
<file name="script.js">
- angular.module('sampleSmartPie', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
+ angular.module('sampleSmartPieResource', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
+ .controller('SampleCtrl', function(){
+ this.config = {
+ resource: 'SampleResource',
+ groupBy: 'category',
+ classes: 'resource',
+ labelFormatter: (labels) => {
+ return labels.map(l => l === '1' ? 'North' : 'Dragon');
+ }
+ };
+ });
+ </file>
+ <file name="backendPoll.js">
+ angular.module('sampleSmartPieResource')
+ .run(function($httpBackend, _){
+ let datas = [
+ {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
+ {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
+ {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1}
+ ];
+
+ $httpBackend.whenGET('/test').respond(200, datas)
+ })
+ .factory('_', function($window){
+ return $window._;
+ })
+ .service('SampleResource', function($resource){
+ return $resource('/test/:id', {id: '@id'});
+ })
+ </file>
+ </example>
+
+ Polling data from API
+
+ <example module="sampleSmartPiePoll">
+ <file name="index.html">
+ <div ng-controller="SampleCtrl as vm">
+ <xos-smart-pie config="vm.config"></xos-smart-pie>
+ </div>
+ </file>
+ <file name="script.js">
+ angular.module('sampleSmartPiePoll', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
.controller('SampleCtrl', function(){
this.config = {
resource: 'SampleResource',
@@ -52,7 +135,7 @@
});
</file>
<file name="backend.js">
- angular.module('sampleSmartPie')
+ angular.module('sampleSmartPiePoll')
.run(function($httpBackend, _){
let mock = [
[
@@ -88,44 +171,6 @@
})
</file>
</example>
-
- <example module="sampleSmartPiePoll">
- <file name="index.html">
- <div ng-controller="SampleCtrl as vm">
- <xos-smart-pie config="vm.config"></xos-smart-pie>
- </div>
- </file>
- <file name="script.js">
- angular.module('sampleSmartPiePoll', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
- .controller('SampleCtrl', function(){
- this.config = {
- resource: 'SampleResource',
- groupBy: 'category',
- labelFormatter: (labels) => {
- return labels.map(l => l === '1' ? 'North' : 'Dragon');
- }
- };
- });
- </file>
- <file name="backendPoll.js">
- angular.module('sampleSmartPiePoll')
- .run(function($httpBackend, _){
- let datas = [
- {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
- {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
- {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1}
- ];
-
- $httpBackend.whenGET('/test').respond(200, datas)
- })
- .factory('_', function($window){
- return $window._;
- })
- .service('SampleResource', function($resource){
- return $resource('/test/:id', {id: '@id'});
- })
- </file>
- </example>
*/
.directive('xosSmartPie', function(){
return {
@@ -142,31 +187,53 @@
`,
bindToController: true,
controllerAs: 'vm',
- controller: function($injector, $timeout, $interval, _){
+ controller: function($injector, $timeout, $interval, $scope, _){
- this.Resource = $injector.get(this.config.resource);
+ if(!this.config.resource && !this.config.data){
+ throw new Error('[xosSmartPie] Please provide a resource or an array of data in the configuration');
+ }
- const getData = () => {
- this.Resource.query().$promise
- .then((res) => {
+ const groupData = (data) => _.groupBy(data, this.config.groupBy);
+ const formatData = (data) => _.reduce(Object.keys(data), (list, group) => list.concat(data[group].length), []);
+ const formatLabels = (data) => angular.isFunction(this.config.labelFormatter) ? this.config.labelFormatter(Object.keys(data)) : Object.keys(data);
- if(!res[0]){
- return;
+ const prepareData = (data) => {
+ // group data
+ let grouped = groupData(data);
+ this.data = formatData(grouped);
+ // create labels
+ this.labels = formatLabels(grouped);
+ }
+
+ if(this.config.resource){
+
+ this.Resource = $injector.get(this.config.resource);
+ const getData = () => {
+ this.Resource.query().$promise
+ .then((res) => {
+
+ if(!res[0]){
+ return;
+ }
+
+ prepareData(res);
+ });
+ }
+
+ getData();
+
+ if(this.config.poll){
+ $interval(() => {getData()}, this.config.poll * 1000)
+ }
+ }
+ else {
+ $scope.$watch(() => this.config.data, (data) => {
+ if(data){
+ prepareData(this.config.data);
}
-
- // group data
- let grouped = _.groupBy(res, this.config.groupBy);
- this.data = _.reduce(Object.keys(grouped), (data, group) => data.concat(grouped[group].length), []);
- // create labels
- this.labels = angular.isFunction(this.config.labelFormatter) ? this.config.labelFormatter(Object.keys(grouped)) : Object.keys(grouped);
- });
+ }, true);
}
- getData();
-
- if(this.config.poll){
- $interval(() => {getData()}, this.config.poll * 1000)
- }
}
};
});
diff --git a/xos/api/import_methods.py b/xos/api/import_methods.py
index 3702f8a..fbcd990 100644
--- a/xos/api/import_methods.py
+++ b/xos/api/import_methods.py
@@ -88,8 +88,10 @@
viewset = view_url[3]
urlpatterns.extend(viewset.get_urlpatterns(api_path="^"+api_path+"/"))
- if not has_index_view:
- urlpatterns.append(url('^' + api_path + '/$', XOSIndexViewSet.as_view({'get': 'list'}, view_urls=view_urls, subdirs=subdirs), name="api_path"+"_index"))
+ # Only add an index_view if 1) the is not already an index view, and
+ # 2) we have found some methods in this directory.
+ if (not has_index_view) and (urlpatterns):
+ urlpatterns.append(url('^' + api_path + '/$', XOSIndexViewSet.as_view({'get': 'list'}, view_urls=view_urls, subdirs=subdirs, api_path=api_path), name=api_path+"_index"))
return urlpatterns
diff --git a/xos/api/service/hpc/__init__.py b/xos/api/service/hpc/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/api/service/hpc/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/api/service/hpc/hpcview.py b/xos/api/service/hpc/hpcview.py
new file mode 100644
index 0000000..3e31e73
--- /dev/null
+++ b/xos/api/service/hpc/hpcview.py
@@ -0,0 +1,210 @@
+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.views import APIView
+from core.models import *
+from services.hpc.models import *
+from services.requestrouter.models import *
+from django.forms import widgets
+from django.core.exceptions import PermissionDenied
+from django.contrib.contenttypes.models import ContentType
+import json
+import socket
+import time
+
+def lookup_tag(service, instance, name, default=None):
+ instance_type = ContentType.objects.get_for_model(instance)
+ t = Tag.objects.filter(service=service, name=name, content_type__pk=instance_type.id, object_id=instance.id)
+ if t:
+ return t[0].value
+ else:
+ return default
+
+def lookup_time(service, instance, name):
+ v = lookup_tag(service, instance, name)
+ if v:
+ return str(time.time() - float(v))
+ else:
+ return None
+
+def json_default(d, default):
+ if not d:
+ return default
+ return json.loads(d)
+
+def compute_config_run(d):
+ if not d:
+ return "null"
+
+ try:
+ d = json.loads(d)
+ except:
+ return "error decoding json '%s'" % str(d)
+
+ status = d.get("status", "null")
+ if status!="success":
+ return status
+
+ config_run = d.get("config.run")
+ if not config_run:
+ return "null"
+
+ try:
+ config_run = max(0, int(time.time()) - int(float(config_run)))
+ except:
+ pass
+
+ return config_run
+
+# from hpc_watcher.py
+def get_public_ip(service, instance):
+ network_name = None
+ if "hpc" in instance.slice.name:
+ network_name = getattr(service, "watcher_hpc_network", None)
+ elif "demux" in instance.slice.name:
+ network_name = getattr(service, "watcher_dnsdemux_network", None)
+ elif "redir" in instance.slice.name:
+ network_name = getattr(service, "watcher_dnsredir_network", None)
+
+ if network_name and network_name.lower()=="nat":
+ return None
+
+ if (network_name is None) or (network_name=="") or (network_name.lower()=="public"):
+ return instance.get_public_ip()
+
+ for ns in instance.ports.all():
+ if (ns.ip) and (ns.network.name==network_name):
+ return ns.ip
+
+ raise ValueError("Couldn't find network %s" % str(network_name))
+
+def getHpcDict(user, pk):
+ hpc = HpcService.objects.get(pk=pk)
+ slices = hpc.slices.all()
+
+ dnsdemux_slice = None
+ dnsredir_slice = None
+ hpc_slice = None
+ for slice in slices:
+ if "dnsdemux" in slice.name:
+ dnsdemux_service = hpc
+ dnsdemux_slice = slice
+ if "dnsredir" in slice.name:
+ dnsredir_service = hpc
+ dnsredir_slice = slice
+ if "hpc" in slice.name:
+ hpc_service = hpc
+ hpc_slice = slice
+
+ if not dnsdemux_slice:
+ rr = RequestRouterService.objects.all()
+ if rr:
+ rr=rr[0]
+ slices = rr.slices.all()
+ for slice in slices:
+ if "dnsdemux" in slice.name:
+ dnsdemux_service = rr
+ dnsdemux_slice = slice
+ if "dnsredir" in slice.name:
+ dnsredir_service = rr
+ dnsredir_slice = slice
+
+ if not dnsredir_slice:
+ print "no dnsredir slice"
+ return
+
+ if not dnsdemux_slice:
+ print "no dnsdemux slice"
+ return
+
+ #dnsdemux_has_public_network = False
+ #for network in dnsdemux_slice.networks.all():
+ # if (network.template) and (network.template.visibility=="public") and (network.template.translation=="none"):
+ # dnsdemux_has_public_network = True
+
+ nameservers = {}
+ for nshc in hpc.hpchealthcheck_set.filter(kind="nameserver"):
+ nameserver = nshc.resource_name
+ try:
+ nameservers[nameserver] = {"name": nameserver, "ip": socket.gethostbyname(nameserver), "hit": False}
+ except:
+ nameservers[nameserver] = {"name": nameserver, "ip": "exception", "hit": False}
+
+ dnsdemux=[]
+ for instance in dnsdemux_slice.instances.all():
+ ip=None
+ try:
+ ip = get_public_ip(dnsdemux_service, instance)
+ except Exception, e:
+ ip = "Exception: " + str(e)
+ if not ip:
+ try:
+ ip = socket.gethostbyname(instance.node.name)
+ except:
+ ip = "??? " + instance.node.name
+
+ instance_nameservers = []
+ for ns in nameservers.values():
+ if ns["ip"]==ip:
+ instance_nameservers.append(ns["name"])
+ ns["hit"]=True
+
+ # now find the dnsredir instance that is also on this node
+ watcherd_dnsredir = "no-redir-instance"
+ for dnsredir_instance in dnsredir_slice.instances.all():
+ if dnsredir_instance.node == instance.node:
+ watcherd_dnsredir = lookup_tag(dnsredir_service, dnsredir_instance, "watcher.watcher.msg")
+
+ watcherd_dnsdemux = lookup_tag(dnsdemux_service, instance, "watcher.watcher.msg")
+
+ dnsdemux.append( {"name": instance.node.name,
+ "watcher.DNS.msg": lookup_tag(dnsdemux_service, instance, "watcher.DNS.msg"),
+ "watcher.DNS.time": lookup_time(dnsdemux_service, instance, "watcher.DNS.time"),
+ "ip": ip,
+ "nameservers": instance_nameservers,
+ "dnsdemux_config_age": compute_config_run(watcherd_dnsdemux),
+ "dnsredir_config_age": compute_config_run(watcherd_dnsredir) })
+
+ hpc=[]
+ for instance in hpc_slice.instances.all():
+ watcherd_hpc = lookup_tag(hpc_service, instance, "watcher.watcher.msg")
+
+ hpc.append( {"name": instance.node.name,
+ "watcher.HPC-hb.msg": lookup_tag(hpc_service, instance, "watcher.HPC-hb.msg"),
+ "watcher.HPC-hb.time": lookup_time(hpc_service, instance, "watcher.HPC-hb.time"),
+ "watcher.HPC-fetch.msg": lookup_tag(hpc_service, instance, "watcher.HPC-fetch.msg"),
+ "watcher.HPC-fetch.time": lookup_time(hpc_service, instance, "watcher.HPC-fetch.time"),
+ "watcher.HPC-fetch.urls": json_default(lookup_tag(hpc_service, instance, "watcher.HPC-fetch-urls.msg"), []),
+ "config_age": compute_config_run(watcherd_hpc),
+
+ })
+
+ return { "id": pk,
+ "dnsdemux": dnsdemux,
+ "hpc": hpc,
+ "nameservers": nameservers,}
+
+
+class HpcList(APIView):
+ method_kind = "list"
+ method_name = "hpcview"
+
+ def get(self, request, format=None):
+ if (not request.user.is_authenticated()):
+ raise PermissionDenied("You must be authenticated in order to use this API")
+ results = []
+ for hpc in HpcService.objects.all():
+ results.append(getHpcDict(request.user, hpc.pk))
+ return Response( results )
+
+class HpcDetail(APIView):
+ method_kind = "detail"
+ method_name = "hpcview"
+
+ def get(self, request, format=None, pk=0):
+ if (not request.user.is_authenticated()):
+ raise PermissionDenied("You must be authenticated in order to use this API")
+ return Response( [getHpcDict(request.user, pk)] )
+
diff --git a/xos/api/xosapi_helpers.py b/xos/api/xosapi_helpers.py
index 8c737cb..aa5c770 100644
--- a/xos/api/xosapi_helpers.py
+++ b/xos/api/xosapi_helpers.py
@@ -6,6 +6,8 @@
from rest_framework import viewsets
from django.conf.urls import patterns, url
from xos.exceptions import *
+from rest_framework.reverse import reverse
+from django.core.urlresolvers import get_script_prefix, resolve, Resolver404
if hasattr(serializers, "ReadOnlyField"):
# rest_framework 3.x
@@ -133,20 +135,32 @@
class XOSIndexViewSet(viewsets.ViewSet):
view_urls=[]
subdirs=[]
+ api_path = None
- def __init__(self, view_urls, subdirs):
+ def __init__(self, view_urls, subdirs, api_path):
self.view_urls = view_urls
self.subdirs = subdirs
+ self.api_path = api_path
super(XOSIndexViewSet, self).__init__()
def list(self, request):
- endpoints = []
+ endpoints = {}
for view_url in self.view_urls:
method_name = view_url[1].split("/")[-1]
- endpoints.append(method_name)
+ method_url = "http://" + request.get_host() + get_script_prefix() + self.api_path + "/" + method_name
+ endpoints[method_name] = method_url
for subdir in self.subdirs:
- endpoints.append(subdir)
+ method_name = subdir
+ method_url = get_script_prefix() + self.api_path + "/" + subdir + "/"
+ # Check to make sure that an endpoint exists at this method_url. This
+ # prunes out subdirs that don't have any methods (like examples/)
+ try:
+ resolve(method_url)
+ except Resolver404:
+ continue
+ method_url = "http://" + request.get_host() + method_url
+ endpoints[method_name] = method_url
- return Response({"endpoints": endpoints})
+ return Response(endpoints)
diff --git a/xos/configurations/frontend/Makefile b/xos/configurations/frontend/Makefile
index 38e077e..7223cf7 100644
--- a/xos/configurations/frontend/Makefile
+++ b/xos/configurations/frontend/Makefile
@@ -39,5 +39,5 @@
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 exec frontend_xos_1 cp /opt/xos/configurations/cord/xos_cord_config /opt/xos/xos_configuration/
+ sudo docker exec frontend_xos_1 cp /opt/xos/configurations/cord-pod/xos_cord_config /opt/xos/xos_configuration/
sudo docker exec frontend_xos_1 touch /opt/xos/xos/settings.py
diff --git a/xos/core/models/plcorebase.py b/xos/core/models/plcorebase.py
index 060570d..76c2e54 100644
--- a/xos/core/models/plcorebase.py
+++ b/xos/core/models/plcorebase.py
@@ -198,8 +198,8 @@
# default values for created and updated are only there to keep evolution
# from failing.
- created = models.DateTimeField(auto_now_add=True, default=timezone.now)
- updated = models.DateTimeField(default=timezone.now)
+ created = models.DateTimeField(auto_now_add=True)
+ updated = models.DateTimeField(auto_now=True)
enacted = models.DateTimeField(null=True, blank=True, default=None)
policed = models.DateTimeField(null=True, blank=True, default=None)
diff --git a/xos/core/xoslib/static/js/vendor/ngXosHelpers.js b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
index 7ff31fe..7985bc5 100644
--- a/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
+++ b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
@@ -258,177 +258,6 @@
*
* Visit http://guide.xosproject.org/devguide/addview/ for more information
*
- * Created by teone on 3/24/16.
- */
-
-(function () {
- 'use strict';
-
- angular.module('xos.uiComponents')
- /**
- * @ngdoc directive
- * @name xos.uiComponents.directive:xosSmartPie
- * @restrict E
- * @description The xos-table directive
- * @param {Object} config The configuration for the component,
- * it is composed by the name of an angular [$resource](https://docs.angularjs.org/api/ngResource/service/$resource)
- * and a field name that is used to group the data.
- * ```
- * {
- resource: 'Users',
- groupBy: 'fieldName',
- classes: 'my-custom-class',
- labelFormatter: (labels) => {
- // here you can format your label,
- // you should return an array with the same order
- return labels;
- }
- }
- * ```
- * @scope
- * @example
- <example module="sampleSmartPie">
- <file name="index.html">
- <div ng-controller="SampleCtrl as vm">
- <xos-smart-pie config="vm.config"></xos-smart-pie>
- </div>
- </file>
- <file name="script.js">
- angular.module('sampleSmartPie', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
- .controller('SampleCtrl', function(){
- this.config = {
- resource: 'SampleResource',
- groupBy: 'category',
- poll: 2,
- labelFormatter: (labels) => {
- return labels.map(l => l === '1' ? 'Active' : 'Banned');
- }
- };
- });
- </file>
- <file name="backend.js">
- angular.module('sampleSmartPie')
- .run(function($httpBackend, _){
- let mock = [
- [
- {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
- {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
- {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1},
- {id: 3, first_name: 'Tyrion', last_name: 'Lannister', category: 1}
- ],
- [
- {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
- {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
- {id: 3, first_name: 'Aria', last_name: 'Stark', category: 2},
- {id: 3, first_name: 'Tyrion', last_name: 'Lannister', category: 2}
- ],
- [
- {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
- {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
- {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1},
- {id: 3, first_name: 'Tyrion', last_name: 'Lannister', category: 2}
- ]
- ];
- $httpBackend.whenGET('/test').respond(function(method, url, data, headers, params) {
- return [200, mock[Math.round(Math.random() * 3)]];
- });
- })
- .factory('_', function($window){
- return $window._;
- })
- .service('SampleResource', function($resource){
- return $resource('/test/:id', {id: '@id'});
- })
- </file>
- </example>
- <example module="sampleSmartPiePoll">
- <file name="index.html">
- <div ng-controller="SampleCtrl as vm">
- <xos-smart-pie config="vm.config"></xos-smart-pie>
- </div>
- </file>
- <file name="script.js">
- angular.module('sampleSmartPiePoll', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
- .controller('SampleCtrl', function(){
- this.config = {
- resource: 'SampleResource',
- groupBy: 'category',
- labelFormatter: (labels) => {
- return labels.map(l => l === '1' ? 'North' : 'Dragon');
- }
- };
- });
- </file>
- <file name="backendPoll.js">
- angular.module('sampleSmartPiePoll')
- .run(function($httpBackend, _){
- let datas = [
- {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
- {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
- {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1}
- ];
- $httpBackend.whenGET('/test').respond(200, datas)
- })
- .factory('_', function($window){
- return $window._;
- })
- .service('SampleResource', function($resource){
- return $resource('/test/:id', {id: '@id'});
- })
- </file>
- </example>
- */
- .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: true,
- controllerAs: 'vm',
- controller: ["$injector", "$timeout", "$interval", "_", function controller($injector, $timeout, $interval, _) {
- var _this = this;
-
- this.Resource = $injector.get(this.config.resource);
-
- var getData = function getData() {
- _this.Resource.query().$promise.then(function (res) {
-
- if (!res[0]) {
- return;
- }
-
- // group data
- var grouped = _.groupBy(res, _this.config.groupBy);
- _this.data = _.reduce(Object.keys(grouped), function (data, group) {
- return data.concat(grouped[group].length);
- }, []);
- // create labels
- _this.labels = angular.isFunction(_this.config.labelFormatter) ? _this.config.labelFormatter(Object.keys(grouped)) : Object.keys(grouped);
- });
- };
-
- getData();
-
- if (this.config.poll) {
- $interval(function () {
- getData();
- }, this.config.poll * 1000);
- }
- }]
- };
- });
-})();
-//# sourceMappingURL=../../../maps/ui_components/smartComponents/smartPie/smartPie.component.js.map
-
-'use strict';
-
-/**
- * © OpenCORD
- *
- * Visit http://guide.xosproject.org/devguide/addview/ for more information
- *
* Created by teone on 4/15/16.
*/
@@ -530,6 +359,247 @@
'use strict';
angular.module('xos.uiComponents')
+ /**
+ * @ngdoc directive
+ * @name xos.uiComponents.directive:xosSmartPie
+ * @restrict E
+ * @description The xos-table directive
+ * @param {Object} config The configuration for the component,
+ * it is composed by the name of an angular [$resource](https://docs.angularjs.org/api/ngResource/service/$resource)
+ * and a field name that is used to group the data.
+ * ```
+ * {
+ resource: 'Users',
+ groupBy: 'fieldName',
+ classes: 'my-custom-class',
+ labelFormatter: (labels) => {
+ // here you can format your label,
+ // you should return an array with the same order
+ return labels;
+ }
+ }
+ * ```
+ * @scope
+ * @example
+
+ Displaying Local data
+ <example module="sampleSmartPieLocal">
+ <file name="index.html">
+ <div ng-controller="SampleCtrlLocal as vm">
+ <xos-smart-pie config="vm.configLocal"></xos-smart-pie>
+ </div>
+ </file>
+ <file name="script.js">
+ angular.module('sampleSmartPieLocal', ['xos.uiComponents'])
+ .factory('_', function($window){
+ return $window._;
+ })
+ .controller('SampleCtrlLocal', function($timeout){
+
+ this.datas = [
+ {id: 1, first_name: 'Jon', last_name: 'aaa', category: 2},
+ {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 1},
+ {id: 3, first_name: 'Aria', last_name: 'Stark', category: 2}
+ ];
+ this.configLocal = {
+ data: [],
+ groupBy: 'category',
+ classes: 'local',
+ labelFormatter: (labels) => {
+ return labels.map(l => l === '1' ? 'North' : 'Dragon');
+ }
+ };
+
+ $timeout(() => {
+ // this need to be triggered in this way just because of ngDoc,
+ // otherwise you can assign data directly in the config
+ this.configLocal.data = this.datas;
+ }, 1)
+ });
+ </file>
+ </example>
+ Fetching data from API
+ <example module="sampleSmartPieResource">
+ <file name="index.html">
+ <div ng-controller="SampleCtrl as vm">
+ <xos-smart-pie config="vm.config"></xos-smart-pie>
+ </div>
+ </file>
+ <file name="script.js">
+ angular.module('sampleSmartPieResource', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
+ .controller('SampleCtrl', function(){
+ this.config = {
+ resource: 'SampleResource',
+ groupBy: 'category',
+ classes: 'resource',
+ labelFormatter: (labels) => {
+ return labels.map(l => l === '1' ? 'North' : 'Dragon');
+ }
+ };
+ });
+ </file>
+ <file name="backendPoll.js">
+ angular.module('sampleSmartPieResource')
+ .run(function($httpBackend, _){
+ let datas = [
+ {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
+ {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
+ {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1}
+ ];
+ $httpBackend.whenGET('/test').respond(200, datas)
+ })
+ .factory('_', function($window){
+ return $window._;
+ })
+ .service('SampleResource', function($resource){
+ return $resource('/test/:id', {id: '@id'});
+ })
+ </file>
+ </example>
+ Polling data from API
+ <example module="sampleSmartPiePoll">
+ <file name="index.html">
+ <div ng-controller="SampleCtrl as vm">
+ <xos-smart-pie config="vm.config"></xos-smart-pie>
+ </div>
+ </file>
+ <file name="script.js">
+ angular.module('sampleSmartPiePoll', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
+ .controller('SampleCtrl', function(){
+ this.config = {
+ resource: 'SampleResource',
+ groupBy: 'category',
+ poll: 2,
+ labelFormatter: (labels) => {
+ return labels.map(l => l === '1' ? 'Active' : 'Banned');
+ }
+ };
+ });
+ </file>
+ <file name="backend.js">
+ angular.module('sampleSmartPiePoll')
+ .run(function($httpBackend, _){
+ let mock = [
+ [
+ {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
+ {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
+ {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1},
+ {id: 3, first_name: 'Tyrion', last_name: 'Lannister', category: 1}
+ ],
+ [
+ {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
+ {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
+ {id: 3, first_name: 'Aria', last_name: 'Stark', category: 2},
+ {id: 3, first_name: 'Tyrion', last_name: 'Lannister', category: 2}
+ ],
+ [
+ {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
+ {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
+ {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1},
+ {id: 3, first_name: 'Tyrion', last_name: 'Lannister', category: 2}
+ ]
+ ];
+ $httpBackend.whenGET('/test').respond(function(method, url, data, headers, params) {
+ return [200, mock[Math.round(Math.random() * 3)]];
+ });
+ })
+ .factory('_', function($window){
+ return $window._;
+ })
+ .service('SampleResource', function($resource){
+ return $resource('/test/:id', {id: '@id'});
+ })
+ </file>
+ </example>
+ */
+ .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: true,
+ controllerAs: 'vm',
+ controller: ["$injector", "$timeout", "$interval", "$scope", "_", function controller($injector, $timeout, $interval, $scope, _) {
+ var _this = 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 groupData = function groupData(data) {
+ return _.groupBy(data, _this.config.groupBy);
+ };
+ var formatData = function formatData(data) {
+ return _.reduce(Object.keys(data), function (list, group) {
+ return list.concat(data[group].length);
+ }, []);
+ };
+ var formatLabels = function formatLabels(data) {
+ return angular.isFunction(_this.config.labelFormatter) ? _this.config.labelFormatter(Object.keys(data)) : Object.keys(data);
+ };
+
+ var prepareData = function prepareData(data) {
+ // group data
+ var grouped = groupData(data);
+ _this.data = formatData(grouped);
+ // create labels
+ _this.labels = formatLabels(grouped);
+ };
+
+ if (this.config.resource) {
+ (function () {
+
+ _this.Resource = $injector.get(_this.config.resource);
+ var getData = function getData() {
+ _this.Resource.query().$promise.then(function (res) {
+
+ if (!res[0]) {
+ return;
+ }
+
+ prepareData(res);
+ });
+ };
+
+ getData();
+
+ if (_this.config.poll) {
+ $interval(function () {
+ getData();
+ }, _this.config.poll * 1000);
+ }
+ })();
+ } else {
+ $scope.$watch(function () {
+ return _this.config.data;
+ }, function (data) {
+ if (data) {
+ prepareData(_this.config.data);
+ }
+ }, true);
+ }
+ }]
+ };
+ });
+})();
+//# sourceMappingURL=../../../maps/ui_components/smartComponents/smartPie/smartPie.component.js.map
+
+'use strict';
+
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+ 'use strict';
+
+ angular.module('xos.uiComponents')
/**
* @ngdoc directive
diff --git a/xos/synchronizers/base/syncstep.py b/xos/synchronizers/base/syncstep.py
index 0e34010..42a9db4 100644
--- a/xos/synchronizers/base/syncstep.py
+++ b/xos/synchronizers/base/syncstep.py
@@ -1,6 +1,7 @@
import os
import base64
from datetime import datetime
+from django.utils import timezone
from xos.config import Config
from xos.logger import Logger, logging
from synchronizers.base.steps import *
@@ -227,7 +228,7 @@
self.delete_record(o)
o.delete(purge=True)
else:
- new_enacted = datetime.now() # Is this the same timezone? XXX
+ new_enacted = timezone.now()
self.sync_record(o)
o.enacted = new_enacted
scratchpad = {'next_run':0, 'exponent':0, 'last_success':time.time()}
diff --git a/xos/xos/apps.py b/xos/xos/apps.py
index 3462990..b38d753 100644
--- a/xos/xos/apps.py
+++ b/xos/xos/apps.py
@@ -9,5 +9,5 @@
{'label': 'Sites', 'icon':'icon-site', 'url': '/admin/core/site/'},
{'label': 'Slices', 'icon':'icon-slice', 'url': '/admin/core/slice/'},
{'label': 'Users', 'icon':'icon-user', 'url': '/admin/core/user/'},
- {'label': 'Services', 'icon':'icon-cog', 'url': '/serviceGrid/'},
+ {'label': 'Services', 'icon':'icon-cog', 'url': '/admin/core/service'},
)
\ No newline at end of file
diff --git a/xos/xos/settings.py b/xos/xos/settings.py
index dad7888..417be81 100644
--- a/xos/xos/settings.py
+++ b/xos/xos/settings.py
@@ -2,6 +2,7 @@
from django import VERSION as DJANGO_VERSION
import socket
import os
+import warnings
from urlparse import urlparse
# Django settings for XOS.
@@ -67,6 +68,12 @@
# In a Windows environment this must be set to your system time zone.
TIME_ZONE = 'America/New_York'
+# Verbose warnings when a naive datetime is used, gives a traceback
+# from: https://docs.djangoproject.com/en/1.9/topics/i18n/timezones/#code
+warnings.filterwarnings(
+ 'error', r"DateTimeField .* received a naive datetime",
+ RuntimeWarning, r'django\.db\.models\.fields')
+
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'