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'