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)