CORD-1312: Generate Synchronizer configuration from xproto

Note: The new dependency graph has not been plugged into the
Synchronizer yet, although it has been tested. The integration task
will be carried out with the upcoming Synchronizer refactor.

Change-Id: Ie3c2a9d59478f3281da8edd33b9347559a1a2ba9
diff --git a/lib/xos-config/xosconfig/synchronizer-config-schema.yaml b/lib/xos-config/xosconfig/synchronizer-config-schema.yaml
index 16c5433..640d61c 100644
--- a/lib/xos-config/xosconfig/synchronizer-config-schema.yaml
+++ b/lib/xos-config/xosconfig/synchronizer-config-schema.yaml
@@ -16,6 +16,8 @@
             enum: ['file', 'console', 'elkstack']
   dependency_graph:
     type: str
+  link_graph:
+    type: str
   steps_dir:
     type: str
   sys_dir:
@@ -77,4 +79,4 @@
       default_flavor:
         type: str
       default_security_group:
-        type: str
\ No newline at end of file
+        type: str
diff --git a/xos/genx/reference/Makefile b/xos/genx/reference/Makefile
new file mode 100644
index 0000000..1cf46b1
--- /dev/null
+++ b/xos/genx/reference/Makefile
@@ -0,0 +1,15 @@
+PREFIX=..
+
+# Replace the line below with the location of xosgen
+%.ok: %.py
+	PYTHONPATH=$(PYTHONPATH):$(PREFIX)/reference python -m $(subst /,.,$(subst .py,,$<))
+
+
+oks = $(tests:.py=.ok)
+
+tests: $(oks)
+	
+.PHONY: clean all init tests
+	
+clean:
+	rm -f $(oks) 
diff --git a/xos/genx/reference/dependency_graph.json b/xos/genx/reference/dependency_graph.json
new file mode 100644
index 0000000..cd12442
--- /dev/null
+++ b/xos/genx/reference/dependency_graph.json
@@ -0,0 +1,157 @@
+{
+    "AddressPool": [
+        "Service"
+    ],
+    "Controller": [
+        "Deployment"
+    ],
+    "ControllerDashboardView": [
+        "Controller",
+		"DashboardView"
+    ],
+    "ControllerImages": [
+        "Image",
+		"Controller"
+    ],
+    "ControllerNetwork": [
+        "Network",
+		"Controller"
+    ],
+    "ControllerSite": [
+        "Site",
+		"Controller"
+    ],
+    "ControllerSitePrivilege": [
+        "Controller",
+		"SitePrivilege"
+    ],
+    "ControllerSlice": [
+        "Controller",
+		"Slice"
+    ],
+    "ControllerSlicePrivilege": [
+        "Controller",
+		"SlicePrivilege"
+    ],
+    "ControllerUser": [
+        "User",
+		"Controller"
+    ],
+    "DashboardView": [
+        "Controller",
+		"Deployment"
+    ],
+    "DeploymentPrivilege": [
+        "User",
+		"Deployment",
+		"DeploymentRole"
+    ],
+    "Flavor": [
+        "Deployment"
+    ],
+    "Image": [
+        "Deployment"
+    ],
+    "ImageDeployments": [
+        "Image",
+		"Deployment"
+    ],
+    "Instance": [
+        "Image",
+		"User",
+		"Slice",
+		"Deployment",
+		"Node",
+		"Flavor",
+		"Instance"
+    ],
+    "Network": [
+        "NetworkTemplate",
+		"Slice",
+		"Slice",
+		"Slice",
+		"Instance"
+    ],
+    "NetworkParameter": [
+        "NetworkParameterType"
+    ],
+    "NetworkSlice": [
+        "Network",
+		"Slice"
+    ],
+    "Node": [
+        "SiteDeployment"
+    ],
+    "NodeLabel": [
+        "Node"
+    ],
+    "Port": [
+        "Network",
+		"Instance"
+    ],
+    "ServiceAttribute": [
+        "Service"
+    ],
+    "ServiceMonitoringAgentInfo": [
+        "Service"
+    ],
+    "ServicePrivilege": [
+        "User",
+		"Service",
+		"ServiceRole"
+    ],
+    "Site": [
+        "Deployment"
+    ],
+    "SiteDeployment": [
+        "Site",
+		"Deployment",
+		"Controller"
+    ],
+    "SitePrivilege": [
+        "User",
+		"Site",
+		"SiteRole"
+    ],
+    "Slice": [
+        "Site",
+		"Service",
+		"User",
+		"Flavor",
+		"Image",
+		"Node"
+    ],
+    "SlicePrivilege": [
+        "User",
+		"Slice",
+		"SliceRole"
+    ],
+    "Tag": [
+        "Service"
+    ],
+    "Tenant": [
+        "Service",
+		"Service",
+		"Tenant",
+		"User",
+		"TenantRoot",
+		"Network"
+    ],
+    "TenantAttribute": [
+        "Tenant"
+    ],
+    "TenantPrivilege": [
+        "User",
+		"Tenant",
+		"TenantRole"
+    ],
+    "TenantRootPrivilege": [
+        "User",
+		"TenantRoot",
+		"TenantRootRole"
+    ],
+    "TenantWithContainer": [
+        "Instance",
+		"User"
+    ],
+}
diff --git a/xos/genx/reference/dependency_walker.py b/xos/genx/reference/dependency_walker.py
new file mode 100644
index 0000000..25e0f5c
--- /dev/null
+++ b/xos/genx/reference/dependency_walker.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+
+# This code has to be cleaned up and wrapped in a class
+
+import json
+import pdb
+from xosconfig import Config
+
+class DependencyWalker:
+    def __init__(self, deps_str=None, root=None, depth=-1):
+        self.missing_links = {}
+
+        if not deps_str:
+            # The 'link' graph is different from the dependenciy graph. 
+            # It includes back-links as well. This is a .json file.
+            # Dependencies are in the format: k
+            dep_graph_file = Config.get('link_graph')
+            deps_str = open(dep_graph_file).read()
+            pass
+
+        self.dependencies = json.loads(deps_str) # FIXME
+        self.compute_inverse_dependencies()
+        self.root = root
+        self.depth = depth
+        self.queue = []
+        self.visited = []
+
+        self.set_forwards()
+
+
+    def set_forwards(self):
+        self.active_dependencies = {k: [v[0] for v in vlst] for k, vlst in self.dependencies.items()}
+
+
+    def set_backwards(self):
+        self.active_dependencies = {k: [v[0] for v in vlst] for k, vlst in self.inv_dependencies.items()}
+
+
+    def compute_inverse_dependencies(self):
+        # Compute inverse dependencies 
+        # Note that these are not identical as "rlinks". rlinks are reverse links declared explicitly in xproto
+        # These are just an inversion of forward dependencies.
+
+        inv_dependencies = {}
+        for k, vals in self.dependencies.items():
+            for dep in vals:
+                inv_dependencies.setdefault(dep[0], set([])).add(k) 
+
+        self.inv_dependencies = inv_dependencies
+
+
+    def __iter__(self):
+        try:
+            queue = []
+            for v in self.active_dependencies[self.root]:
+                if v not in queue:
+                    queue.append(v)
+            self.queue = zip([self.depth]*len(queue), queue)
+        except KeyError, TypeError:
+            self.queue = []
+
+        return self
+
+
+    def next(self):
+        if not self.queue:
+            raise StopIteration
+        else:
+            depth, n = self.queue.pop()
+
+            try:
+                # Nothing more to see
+                if depth==0:
+                    raise KeyError
+
+                peers = self.active_dependencies[n]
+            except KeyError:
+                peers = []
+
+            self.visited.append(n)
+
+            unseen_peers = [i for i in peers if i not in self.visited and i not in [j[1] for j in self.queue]]
+            self.queue.extend([(depth-1,v) for v in unseen_peers])
+
+            return n
+
+if __name__=='__main__':
+    x = raw_input()
+    dg = DependencyWalker('Slice', int(x))
+    for i in dg:
+        print i
diff --git a/xos/genx/reference/link_graph.json b/xos/genx/reference/link_graph.json
new file mode 100644
index 0000000..56d81ac
--- /dev/null
+++ b/xos/genx/reference/link_graph.json
@@ -0,0 +1,146 @@
+{
+    "AddressPool": [
+        ["Service", "service", "addresspools"]        
+        
+    ],
+    "Controller": [
+        ["Deployment", "deployment", "controllerdeployments"],        
+        ["ControllerDashboardView", "controllerdashboardviews", "controller"],["ControllerImages", "controllerimages", "controller"],["ControllerNetwork", "controllernetworks", "controller"],["ControllerSite", "controllersite", "controller"],["ControllerSitePrivilege", "controllersiteprivileges", "controller"],["ControllerSlice", "controllerslices", "controller"],["ControllerSlicePrivilege", "controllersliceprivileges", "controller"],["ControllerUser", "controllersusers", "controller"],["DashboardView", "dashboardviews", "controllers"],["SiteDeployment", "sitedeployments", "controller"]
+    ],
+    "ControllerDashboardView": [
+        ["Controller", "controller", "controllerdashboardviews"],["DashboardView", "dashboardView", "controllerdashboardviews"]        
+        
+    ],
+    "ControllerImages": [
+        ["Image", "image", "controllerimages"],["Controller", "controller", "controllerimages"]        
+        
+    ],
+    "ControllerNetwork": [
+        ["Network", "network", "controllernetworks"],["Controller", "controller", "controllernetworks"]        
+        
+    ],
+    "ControllerSite": [
+        ["Site", "site", "controllersite"],["Controller", "controller", "controllersite"]        
+        
+    ],
+    "ControllerSitePrivilege": [
+        ["Controller", "controller", "controllersiteprivileges"],["SitePrivilege", "site_privilege", "controllersiteprivileges"]        
+        
+    ],
+    "ControllerSlice": [
+        ["Controller", "controller", "controllerslices"],["Slice", "slice", "controllerslices"]        
+        
+    ],
+    "ControllerSlicePrivilege": [
+        ["Controller", "controller", "controllersliceprivileges"],["SlicePrivilege", "slice_privilege", "controllersliceprivileges"]        
+        
+    ],
+    "ControllerUser": [
+        ["User", "user", "controllerusers"],["Controller", "controller", "controllersusers"]        
+        
+    ],
+    "DashboardView": [
+        ["Controller", "controllers", "dashboardviews"],["Deployment", "deployments", "dashboardviews"],        
+        ["ControllerDashboardView", "controllerdashboardviews", "dashboardView"]
+    ],
+    "DeploymentPrivilege": [
+        ["User", "user", "deploymentprivileges"],["Deployment", "deployment", "deploymentprivileges"],["DeploymentRole", "role", "deploymentprivileges"]        
+        
+    ],
+    "Flavor": [
+        ["Deployment", "deployments", "flavors"],        
+        ["Instance", "instance", "flavor"],["Slice", "slices", "default_flavor"]
+    ],
+    "Image": [
+        ["Deployment", "deployments", "images"],        
+        ["ControllerImages", "controllerimages", "image"],["ImageDeployments", "imagedeployments", "image"],["Instance", "instances", "image"],["Slice", "slices", "default_image"]
+    ],
+    "ImageDeployments": [
+        ["Image", "image", "imagedeployments"],["Deployment", "deployment", "imagedeployments"]        
+        
+    ],
+    "Instance": [
+        ["Image", "image", "instances"],["User", "creator", "instances"],["Slice", "slice", "instances"],["Deployment", "deployment", "instance_deployment"],["Node", "node", "instances"],["Flavor", "flavor", "instance"],["Instance", "parent", "instance"],        
+        ["Instance", "instance", "parent"],["Network", "networks", "instances"],["Port", "ports", "instance"],["TenantWithContainer", "+", "instance"]
+    ],
+    "Network": [
+        ["NetworkTemplate", "template", "network"],["Slice", "owner", "ownedNetworks"],["Slice", "permitted_slices", "availableNetworks"],["Slice", "slices", "networks"],["Instance", "instances", "networks"],        
+        ["ControllerNetwork", "controllernetworks", "network"],["NetworkSlice", "networkslices", "network"],["Port", "links", "network"],["Tenant", "subscribed_tenants", "subscriber_network"]
+    ],
+    "NetworkParameter": [
+        ["NetworkParameterType", "parameter", "networkparameters"]        
+        
+    ],
+    "NetworkSlice": [
+        ["Network", "network", "networkslices"],["Slice", "slice", "networkslices"]        
+        
+    ],
+    "Node": [
+        ["SiteDeployment", "site_deployment", "nodes"],        
+        ["Instance", "instances", "node"],["NodeLabel", "nodelabels", "node"],["Slice", "slices", "default_node"]
+    ],
+    "NodeLabel": [
+        ["Node", "node", "nodelabels"]        
+        
+    ],
+    "Port": [
+        ["Network", "network", "links"],["Instance", "instance", "ports"]        
+        
+    ],
+    "ServiceAttribute": [
+        ["Service", "service", "serviceattributes"]        
+        
+    ],
+    "ServiceMonitoringAgentInfo": [
+        ["Service", "service", "servicemonitoringagents"]        
+        
+    ],
+    "ServicePrivilege": [
+        ["User", "user", "serviceprivileges"],["Service", "service", "serviceprivileges"],["ServiceRole", "role", "serviceprivileges"]        
+        
+    ],
+    "Site": [
+        ["Deployment", "deployments", "sites"],        
+        ["ControllerSite", "controllersite", "site"],["SiteDeployment", "sitedeployments", "site"],["SitePrivilege", "siteprivileges", "site"],["Slice", "slices", "site"]
+    ],
+    "SiteDeployment": [
+        ["Site", "site", "sitedeployments"],["Deployment", "deployment", "sitedeployments"],["Controller", "controller", "sitedeployments"],        
+        ["Node", "nodes", "site_deployment"]
+    ],
+    "SitePrivilege": [
+        ["User", "user", "siteprivileges"],["Site", "site", "siteprivileges"],["SiteRole", "role", "siteprivileges"],        
+        ["ControllerSitePrivilege", "controllersiteprivileges", "site_privilege"]
+    ],
+    "Slice": [
+        ["Site", "site", "slices"],["Service", "service", "slices"],["User", "creator", "slices"],["Flavor", "default_flavor", "slices"],["Image", "default_image", "slices"],["Node", "default_node", "slices"],        
+        ["ControllerSlice", "controllerslices", "slice"],["Instance", "instances", "slice"],["Network", "ownedNetworks", "owner"],["Network", "availableNetworks", "permitted_slices"],["Network", "networks", "slices"],["NetworkSlice", "networkslices", "slice"],["SlicePrivilege", "sliceprivileges", "slice"]
+    ],
+    "SlicePrivilege": [
+        ["User", "user", "sliceprivileges"],["Slice", "slice", "sliceprivileges"],["SliceRole", "role", "sliceprivileges"],        
+        ["ControllerSlicePrivilege", "controllersliceprivileges", "slice_privilege"]
+    ],
+    "Tag": [
+        ["Service", "service", "tags"]        
+        
+    ],
+    "Tenant": [
+        ["Service", "provider_service", "provided_tenants"],["Service", "subscriber_service", "subscribed_tenants"],["Tenant", "subscriber_tenant", "subscribed_tenants"],["User", "subscriber_user", "subscribed_tenants"],["TenantRoot", "subscriber_root", "subscribed_tenants"],["Network", "subscriber_network", "subscribed_tenants"],        
+        ["Tenant", "subscribed_tenants", "subscriber_tenant"],["TenantAttribute", "tenantattributes", "tenant"],["TenantPrivilege", "tenantprivileges", "tenant"]
+    ],
+    "TenantAttribute": [
+        ["Tenant", "tenant", "tenantattributes"]        
+        
+    ],
+    "TenantPrivilege": [
+        ["User", "user", "tenantprivileges"],["Tenant", "tenant", "tenantprivileges"],["TenantRole", "role", "tenantprivileges"]        
+        
+    ],
+    "TenantRootPrivilege": [
+        ["User", "user", "tenant_root_privileges"],["TenantRoot", "tenant_root", "tenant_root_privileges"],["TenantRootRole", "role", "tenant_root_privileges"]        
+        
+    ],
+    "TenantWithContainer": [
+        ["Instance", "instance", "+"],["User", "creator", "+"]        
+        
+    ]
+}
diff --git a/xos/genx/reference/tests/__init__.py b/xos/genx/reference/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/genx/reference/tests/__init__.py
diff --git a/xos/genx/reference/tests/traverse_test.py b/xos/genx/reference/tests/traverse_test.py
new file mode 100644
index 0000000..1c069a8
--- /dev/null
+++ b/xos/genx/reference/tests/traverse_test.py
@@ -0,0 +1,20 @@
+from dependency_walker import DependencyWalker
+import unittest
+
+class DependencyWalkerTest(unittest.TestCase):
+    def test_unbounded(self):
+        deps = '{"10": [["4", "ignore", "ignore"], ["3", "ignore", "ignore"]], "1": [["2", "ignore", "ignore"]], "3": [["5", "ignore", "ignore"]], "2": [["1", "ignore", "ignore"]], "5": [["3", "ignore", "ignore"]], "4": [], "7": [], "6": [["2", "ignore", "ignore"], ["6", "ignore", "ignore"], ["9", "ignore", "ignore"], ["5", "ignore", "ignore"]], "9": [["3", "ignore", "ignore"]], "8": []}'
+        dw = DependencyWalker(deps, '10')
+        walk = sorted(dw)
+        self.assertEqual(walk, ['3','4','5'])
+
+    def test_bounded_depth(self):
+        deps = '{"10": [["4", "ignore", "ignore"], ["3", "ignore", "ignore"]], "1": [["2", "ignore", "ignore"]], "3": [["5", "ignore", "ignore"]], "2": [["1", "ignore", "ignore"]], "5": [["3", "ignore", "ignore"]], "4": [], "7": [], "6": [["2", "ignore", "ignore"], ["6", "ignore", "ignore"], ["9", "ignore", "ignore"], ["5", "ignore", "ignore"]], "9": [["3", "ignore", "ignore"]], "8": []}'
+        dw = DependencyWalker(deps, '10', depth=0)
+        walk = sorted(dw)
+        self.assertEqual(walk, ['3','4'])
+   
+if __name__ == '__main__':
+    unittest.main()
+
+
diff --git a/xos/genx/targets/link-graph.xtarget b/xos/genx/targets/link-graph.xtarget
new file mode 100644
index 0000000..04c9dba
--- /dev/null
+++ b/xos/genx/targets/link-graph.xtarget
@@ -0,0 +1,14 @@
+{
+{%- for model in proto.messages %}
+{%- if model.links %}
+    "{{ model.name }}": [
+        {% for l in model.links -%}
+            ["{{ l.peer }}", "{{ l.src_port }}", "{{ l.dst_port }}"]{% if not loop.last %},{% endif %}
+        {%- endfor %}
+        {%- if model.rlinks %},{% endif %}        
+        {% for l in model.rlinks -%}
+            ["{{ l.peer }}", "{{ l.src_port }}", "{{ l.dst_port }}"]{% if not loop.last %},{% endif %}
+        {%- endfor %}
+    ],{% endif -%}
+{% endfor %}
+}
diff --git a/xos/genx/targets/model-deps-graphviz.xtarget b/xos/genx/targets/model-deps-graphviz.xtarget
new file mode 100644
index 0000000..429c9f4
--- /dev/null
+++ b/xos/genx/targets/model-deps-graphviz.xtarget
@@ -0,0 +1,7 @@
+digraph {{ context.app_name }} {
+{%- for model in proto.messages %}
+    {%- for l in model.links %}
+        "{{ model.name }}" -> "{{ l.peer }}" [label="{{ l.src_port }}"];
+    {%- endfor %}
+{%- endfor %}
+}
diff --git a/xos/genx/targets/model-deps.xtarget b/xos/genx/targets/model-deps.xtarget
new file mode 100644
index 0000000..65a3742
--- /dev/null
+++ b/xos/genx/targets/model-deps.xtarget
@@ -0,0 +1,8 @@
+{
+{%- for model in proto.messages %}
+{%- if model.links %}
+    "{{ model.name }}": [
+        {{ model.links | map(attribute='peer') | format_list("\"%s\"") |join(',\n\t\t') }}
+    ],{% endif -%}
+{% endfor %}
+}
diff --git a/xos/genx/tool/Makefile b/xos/genx/tool/Makefile
index 988c1af..8f667ee 100644
--- a/xos/genx/tool/Makefile
+++ b/xos/genx/tool/Makefile
@@ -3,6 +3,9 @@
 XOSGEN=python $(PREFIX)/tool/xosgen
 
 DJANGO_TARGET=$(PREFIX)/targets/django-split.xtarget
+DOT_TARGET=$(PREFIX)/targets/model-deps-graphviz.xtarget
+DEP_TARGET=$(PREFIX)/targets/model-deps.xtarget
+
 INIT_TARGET=$(PREFIX)/targets/init.xtarget
 XPROTOS_TMP := $(shell mktemp)
 
@@ -14,6 +17,18 @@
 %.ok: %.py
 	PYTHONPATH=$(PYTHONPATH):$(PREFIX)/tool python -m $(subst /,.,$(subst .py,,$<))
 
+# Rule to produce graphviz dot
+%.dot: %.xproto
+	$(XOSGEN) --target $(DOT_TARGET) $< > $@
+
+# Rule to produce model dependencies
+%.json: %.xproto
+	$(XOSGEN) --target $(DEP_TARGET) $< > $@
+
+# Rule to produce json dependencies
+%.ok: %.py
+	PYTHONPATH=$(PYTHONPATH):$(PREFIX)/tool python -m $(subst /,.,$(subst .py,,$<))
+
 # List of xprotos 
 xprotos = $(wildcard *.xproto)
 pys = $(xprotos:.xproto=.py)
diff --git a/xos/genx/tool/generator.py b/xos/genx/tool/generator.py
index e76bf87..72eb65a 100755
--- a/xos/genx/tool/generator.py
+++ b/xos/genx/tool/generator.py
@@ -17,6 +17,7 @@
 class XOSGenerator:
     def __init__(self, args):
         self.args = args
+	self.input = None
 
     def file_exists(self):
         def file_exists2(name):
@@ -35,9 +36,16 @@
                 path = name
             return open(path).read()
         return include_file2
+
         # FIXME: Support templates in the future
         #return jinja2.Markup(loader.get_source(env, name)[0])
 
+    def format_list(self):
+	def format_list2(input_list, format_string, arguments=[]):
+    	    return [format_string % tuple(arguments + [s]) for s in input_list]
+	return format_list2
+
+
     def generate(self):
         try:
             parser = plyxproto.ProtobufAnalyzer()
@@ -61,7 +69,8 @@
             os_template_env.globals['include_file'] = self.include_file() # Generates a function
             os_template_env.globals['file_exists'] = self.file_exists() # Generates a function
             os_template_env.filters['yaml'] = yaml.dump
-
+            os_template_env.globals['zip'] = zip
+            os_template_env.filters['format_list'] = self.format_list() # Generates a function
 
             for f in dir(lib):
                 if f.startswith('xproto'):
diff --git a/xos/tools/dmdot b/xos/tools/dmdot
deleted file mode 100755
index d0e6566..0000000
--- a/xos/tools/dmdot
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/usr/bin/python
-
-import os
-import pdb
-import sys
-import json
-
-sys.path.append('.')
-
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
-
-from django.db.models.fields.related import ForeignKey
-
-# try to make sure we're running from the right place
-if (not os.path.exists("core")):
-   if (os.path.exists("../core")):
-      os.chdir("..")
-   else:
-      print >> sys.stderr, "Are you sure you're running dmdot from the root of an XOS installation"
-      sys.exit(-1)
-
-# defaults
-apps = ["core", "services.hpc", "services.requestrouter", "services.onos"]
-output = "-json"
-
-# syntax: dmdot [-json | -dot] [app_name]
-
-# poor man's argument parser
-for arg in sys.argv[1:]:
-    if arg.startswith("-"):
-        output = arg
-    else:
-        apps+= [arg]
-
-model_classes = []
-class_names = []
-lower_class_names = {}
-synonyms = {
-	'user':'creator'
-}
-
-for app in apps:
-	app = app + ".models"
-	#models_module = imp.load_source(app, ".")
-	models_module = __import__(app)
-	for part in app.split(".")[1:]:
-	    if hasattr(models_module, "XOSBase"):
-		break
-	    models_module = getattr(models_module,part)
-
-	XOSBase = getattr(models_module,"XOSBase")
-
-	for classname in dir(models_module):
-		c = getattr(models_module, classname, None)
-		if type(c)==type(XOSBase):
-			model_classes.append(c)
-			class_names.append(c.__name__)
-			lower_class_names[c.__name__.lower()] = c
-			try:
-				synonym = synonyms[c.__name__.lower()]
-				lower_class_names[synonym] = c
-			except: 
-				pass    
-				
-
-# django doesn't use the correct case in field.name.title() for objects that
-# have CamelCased class names. So, compare everything in lower case.
-
-if (output=='-dot'):
-        print "digraph plstack {";
-        for c in model_classes:
-                fields = c._meta.fields
-
-                for f in fields:
-                        if type(f)==ForeignKey and f.name.lower().split('_') in lower_class_names:
-                                linked_class = lower_class_names[f.name.lower()]
-				if ('backref' in f.name):
-                                	print '\t"%s"->"%s";'%(linked_class.__name__,c.__name__)
-				else:
-                                	print '\t"%s"->"%s";'%(c.__name__,linked_class.__name__)
-        print "}\n";
-elif (output=='-json'):
-        d = {}
-        for c in model_classes:
-                fields = c._meta.fields
-		
-                for f in fields:
-			field_type = f.name.lower().split('_')[0]
-                        if type(f)==ForeignKey and field_type in lower_class_names:
-                                linked_class = lower_class_names[field_type]
-				if ('backref' in f.name.lower()):
-					a = linked_class.__name__
-					b = c.__name__
-				else:
-					b = linked_class.__name__
-					a = c.__name__
-
-                                try:
-					if (b not in d[a]):
-                                        	d[a].append(b)
-                                except KeyError:
-                                        d[c.__name__]=[linked_class.__name__]
-        #d['ControllerNetwork'].append('SliceDeployments')
-        print json.dumps(d,indent=4)
-        
-        
diff --git a/xos/tools/mldeps b/xos/tools/mldeps
deleted file mode 100755
index 12a0edc..0000000
--- a/xos/tools/mldeps
+++ /dev/null
@@ -1,132 +0,0 @@
-#!/usr/bin/python
-
-import os
-import pdb
-import sys
-import json
-
-sys.path.append('.')
-
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
-
-from django.db.models.fields.related import ForeignKey
-
-# try to make sure we're running from the right place
-if (not os.path.exists("core")):
-    if (os.path.exists("../core")):
-        os.chdir("..")
-    else:
-        print >> sys.stderr, "Are you sure you're running dmdot from the root of an XOS installation"
-        sys.exit(-1)
-
-from core.models import ModelLink
-
-# defaults
-apps = ["core"]#, "services.hpc", "services.requestrouter", "services.onos"]
-output = "-json"
-
-# syntax: mldeps [-json | -dot] [app_name]
-
-# poor man's argument parser
-for arg in sys.argv[1:]:
-    if arg.startswith("-"):
-        output = arg
-    else:
-        apps+= [arg]
-
-model_classes = []
-class_names = []
-lower_class_names = {}
-synonyms = {
-        'user':'creator'
-}
-
-for app in apps:
-    app = app + ".models"
-    #models_module = imp.load_source(app, ".")
-    models_module = __import__(app)
-    for part in app.split(".")[1:]:
-        if hasattr(models_module, "XOSBase"):
-            break
-        models_module = getattr(models_module,part)
-
-    XOSBase = getattr(models_module,"XOSBase")
-
-    for classname in dir(models_module):
-        c = getattr(models_module, classname, None)
-        if type(c)==type(XOSBase):
-            model_classes.append(c)
-            class_names.append(c.__name__)
-            lower_class_names[c.__name__.lower()] = c
-            try:
-                synonym = synonyms[c.__name__.lower()]
-                lower_class_names[synonym] = c
-            except:
-                pass
-
-# django doesn't use the correct case in field.name.title() for objects that
-# have CamelCased class names. So, compare everything in lower case.
-
-if (output=='-dot'):
-    print "digraph plstack {";
-    for c in model_classes:
-        fields = c._meta.fields
-
-        for f in fields:
-            if type(f)==ForeignKey and f.name.lower().split('_') in lower_class_names:
-                linked_class = lower_class_names[f.name.lower()]
-                if ('backref' in f.name):
-                    print '\t"%s"->"%s";'%(linked_class.__name__,c.__name__)
-                else:
-                    print '\t"%s"->"%s";'%(c.__name__,linked_class.__name__)
-    print "}\n";
-elif (output=='-json'):
-    d = {}
-    tl = {}
-    for c in model_classes:
-        fields = c._meta.fields
-        try:
-            exp_links = c.xos_links
-        except AttributeError:
-            exp_links = []
-        for f in fields:
-            field_type = f.name.lower().split('_')[0]
-            if type(f)==ForeignKey and field_type in lower_class_names:
-                linked_class = lower_class_names[field_type]
-
-
-                if ('backref' in f.name.lower()):
-                    a = linked_class.__name__
-                    b = c.__name__
-                else:
-                    b = linked_class.__name__
-                    a = c.__name__
-
-                try:
-
-                    if (b not in d[a]):
-                        d[a].append(b)
-                except KeyError:
-                    d[c.__name__]=[linked_class.__name__]
-
-        for l in exp_links:
-            linked_class = l.dest
-            if (type(linked_class)==str):
-                linked_class = lower_class_names[linked_class.lower()]
-            via = l.via
-            if ('backref' in via):
-                a = linked_class.__name__
-                b = c.__name__
-            else:
-                b = linked_class.__name__
-                a = c.__name__
-
-            try:
-                if (b not in tl[a]):
-                    tl[a].append(b)
-            except KeyError:
-                tl[c.__name__]=[linked_class.__name__]
-
-
-    #d['ControllerNetwork'].append('SliceDeployments')
-    print json.dumps(tl,indent=4)