From 8914ed95fc8fa44771f5f3ec827e325a5855b60a Mon Sep 17 00:00:00 2001 From: Tim Schnell Date: Tue, 9 Jul 2013 17:09:58 -0500 Subject: [PATCH] Adding Heat Resource Topology to Horizon Change-Id: Ie9f2040850df3d7f1fcefe68430e9103c972f80f Implements: blueprint heat-ui-resource-topology --- horizon/static/horizon/js/horizon.heattop.js | 275 ++++++++++++++++++ horizon/templates/horizon/_scripts.html | 1 + .../dashboards/project/stacks/api.py | 84 ++++++ .../dashboards/project/stacks/mappings.py | 62 ++++ .../dashboards/project/stacks/sro.py | 31 ++ .../dashboards/project/stacks/tabs.py | 18 +- .../templates/stacks/_detail_topology.html | 9 + .../templates/stacks/_resource_info.html | 10 + .../stacks/templates/stacks/_stack_info.html | 16 + .../dashboards/project/stacks/urls.py | 4 + .../dashboards/project/stacks/views.py | 2 + .../static/dashboard/img/db-gray.gif | Bin 0 -> 12495 bytes .../static/dashboard/img/db-gray.svg | 85 ++++++ .../static/dashboard/img/db-green.svg | 85 ++++++ .../static/dashboard/img/db-red.svg | 85 ++++++ .../static/dashboard/img/lb-gray.gif | Bin 0 -> 8447 bytes .../static/dashboard/img/lb-gray.svg | 43 +++ .../static/dashboard/img/lb-green.svg | 43 +++ .../static/dashboard/img/lb-red.svg | 43 +++ .../static/dashboard/img/server-gray.gif | Bin 0 -> 7416 bytes .../static/dashboard/img/server-gray.svg | 50 ++++ .../static/dashboard/img/server-green.svg | 50 ++++ .../static/dashboard/img/server-red.svg | 50 ++++ .../static/dashboard/img/stack-gray.gif | Bin 0 -> 14409 bytes .../static/dashboard/img/stack-gray.svg | 73 +++++ .../static/dashboard/img/stack-green.svg | 82 ++++++ .../static/dashboard/img/stack-red.svg | 92 ++++++ .../static/dashboard/img/unknown-gray.gif | Bin 0 -> 10805 bytes .../static/dashboard/img/unknown-green.svg | 33 +++ .../static/dashboard/img/unknown-red.svg | 33 +++ .../static/dashboard/less/horizon.less | 16 + 31 files changed, 1374 insertions(+), 1 deletion(-) create mode 100644 horizon/static/horizon/js/horizon.heattop.js create mode 100644 openstack_dashboard/dashboards/project/stacks/api.py create mode 100644 openstack_dashboard/dashboards/project/stacks/sro.py create mode 100644 openstack_dashboard/dashboards/project/stacks/templates/stacks/_detail_topology.html create mode 100644 openstack_dashboard/dashboards/project/stacks/templates/stacks/_resource_info.html create mode 100644 openstack_dashboard/dashboards/project/stacks/templates/stacks/_stack_info.html create mode 100644 openstack_dashboard/static/dashboard/img/db-gray.gif create mode 100644 openstack_dashboard/static/dashboard/img/db-gray.svg create mode 100644 openstack_dashboard/static/dashboard/img/db-green.svg create mode 100644 openstack_dashboard/static/dashboard/img/db-red.svg create mode 100644 openstack_dashboard/static/dashboard/img/lb-gray.gif create mode 100644 openstack_dashboard/static/dashboard/img/lb-gray.svg create mode 100644 openstack_dashboard/static/dashboard/img/lb-green.svg create mode 100644 openstack_dashboard/static/dashboard/img/lb-red.svg create mode 100644 openstack_dashboard/static/dashboard/img/server-gray.gif create mode 100644 openstack_dashboard/static/dashboard/img/server-gray.svg create mode 100644 openstack_dashboard/static/dashboard/img/server-green.svg create mode 100644 openstack_dashboard/static/dashboard/img/server-red.svg create mode 100644 openstack_dashboard/static/dashboard/img/stack-gray.gif create mode 100644 openstack_dashboard/static/dashboard/img/stack-gray.svg create mode 100644 openstack_dashboard/static/dashboard/img/stack-green.svg create mode 100644 openstack_dashboard/static/dashboard/img/stack-red.svg create mode 100644 openstack_dashboard/static/dashboard/img/unknown-gray.gif create mode 100644 openstack_dashboard/static/dashboard/img/unknown-green.svg create mode 100644 openstack_dashboard/static/dashboard/img/unknown-red.svg diff --git a/horizon/static/horizon/js/horizon.heattop.js b/horizon/static/horizon/js/horizon.heattop.js new file mode 100644 index 0000000000..baf9e72c6a --- /dev/null +++ b/horizon/static/horizon/js/horizon.heattop.js @@ -0,0 +1,275 @@ +/** + * + * HeatTop JS Framework + * Dependencies: jQuery 1.7.1 or later, d3 v3 or later + * Date: June 2013 + * Description: JS Framework that subclasses the D3 Force Directed Graph library to create + * Heat-specific objects and relationships with the purpose of displaying + * Stacks, Resources, and related Properties in a Resource Topology Graph. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + not use this file except in compliance with the License. You may obtain + a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + License for the specific language governing permissions and limitations + under the License. +*/ + +var container = "#heat_resource_topology"; + +if ($(container).length){ + var width = $(container).width(), + height = 500, + stack_id = $("#stack_id").data("stack_id"), + ajax_url = '/project/stacks/get_d3_data/'+stack_id+'/', + graph = $("#d3_data").data("d3_data"), + force = d3.layout.force() + .nodes(graph.nodes) + .links([]) + .gravity(0.1) + .charge(-2000) + .linkDistance(100) + .size([width, height]) + .on("tick",tick), + svg = d3.select(container).append("svg") + .attr("width", width) + .attr("height", height), + node = svg.selectAll(".node"), + link = svg.selectAll(".link"), + needs_update = false, + nodes = force.nodes(), + links = force.links(); + + build_links(); + update(); + + + function update(){ + node = node.data(nodes, function(d){return d.name}); + link = link.data(links); + + var nodeEnter = node.enter().append("g") + .attr("class", "node") + .attr("node_name", function(d){ return d.name }) + .attr("node_id", function(d){ return d.instance }) + .call(force.drag); + + nodeEnter.append("image") + .attr("xlink:href", function(d) { return d.image; }) + .attr("id", function(d){return "image_"+ d.name}) + .attr("x", function(d) { return d.image_x; }) + .attr("y", function(d) { return d.image_y; }) + .attr("width", function(d) { return d.image_size; }) + .attr("height", function(d) { return d.image_size; }); + node.exit().remove(); + + link.enter().insert("svg:line", "g.node") + .attr("class", "link") + .style("stroke-width", function(d) { return Math.sqrt(d.value); }); + link.exit().remove(); + //Setup click action for all nodes + node.on("mouseover", function(d) { + $("#info_box").html(d.info_box); + current_info = d.name; + }); + node.on("mouseout", function(d) { + $("#info_box").html(''); + }); + + force.start(); + } + function tick() { + link.attr("x1", function(d) { return d.source.x; }) + .attr("y1", function(d) { return d.source.y; }) + .attr("x2", function(d) { return d.target.x; }) + .attr("y2", function(d) { return d.target.y; }); + + node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); + } + + //Load initial Stack box + $("#stack_box").html(graph.stack.info_box); + //On Page load, set Action In Progress + var in_progress = false; + set_in_progress(graph.stack, node); + + //If status is In Progress, start AJAX polling + var poll_time = 0; + if (in_progress == true){poll_time = 3000;} + else {poll_time = 30000;} + ajax_poll(poll_time); + + function set_in_progress(stack, nodes) { + if (stack.in_progress == true){in_progress = true;} + for (var i=0;i + {% block custom_js_files %}{% endblock %} {% endcompress %} diff --git a/openstack_dashboard/dashboards/project/stacks/api.py b/openstack_dashboard/dashboards/project/stacks/api.py new file mode 100644 index 0000000000..1572b5a984 --- /dev/null +++ b/openstack_dashboard/dashboards/project/stacks/api.py @@ -0,0 +1,84 @@ +import json +import logging + +from django.http import HttpResponse + +from openstack_dashboard.api.heat import resources_list +from openstack_dashboard.api.heat import stack_get + +from openstack_dashboard.dashboards.project.stacks.mappings \ + import get_resource_image +from openstack_dashboard.dashboards.project.stacks.mappings \ + import get_resource_status +from openstack_dashboard.dashboards.project.stacks.sro import resource_info +from openstack_dashboard.dashboards.project.stacks.sro import stack_info + + +LOG = logging.getLogger(__name__) + + +class Stack(object): + pass + + +def d3_data(request, stack_id=''): + try: + stack = stack_get(request, stack_id) + except: + stack = Stack() + stack.id = stack_id + stack.stack_name = request.session.get('stack_name', '') + stack.stack_status = 'DELETE_COMPLETE' + stack.stack_status_reason = 'DELETE_COMPLETE' + + try: + resources = resources_list(request, stack.stack_name) + except: + resources = [] + + d3_data = {"nodes": [], "stack": {}} + if stack: + stack_image = get_resource_image(stack.stack_status, 'stack') + stack_node = { + 'stack_id': stack.id, + 'name': stack.stack_name, + 'status': stack.stack_status, + 'image': stack_image, + 'image_size': 60, + 'image_x': -30, + 'image_y': -30, + 'text_x': 40, + 'text_y': ".35em", + 'in_progress': True if (get_resource_status(stack.stack_status) == + 'IN_PROGRESS') else False, + 'info_box': stack_info(stack, stack_image) + } + d3_data['stack'] = stack_node + + if resources: + for resource in resources: + resource_image = get_resource_image(resource.resource_status, + resource.resource_type) + in_progress = True if ( + get_resource_status(resource.resource_status) + == 'IN_PROGRESS') else False + resource_node = { + 'name': resource.logical_resource_id, + 'status': resource.resource_status, + 'image': resource_image, + 'required_by': resource.required_by, + 'image_size': 50, + 'image_x': -25, + 'image_y': -25, + 'text_x': 35, + 'text_y': ".35em", + 'in_progress': in_progress, + 'info_box': resource_info(resource) + } + d3_data['nodes'].append(resource_node) + return json.dumps(d3_data) + + +def get_d3_data(request, stack_id=''): + return HttpResponse(d3_data(request, stack_id=stack_id), + content_type="application/json") diff --git a/openstack_dashboard/dashboards/project/stacks/mappings.py b/openstack_dashboard/dashboards/project/stacks/mappings.py index 5b4f9ec7e4..ac6d526ac4 100644 --- a/openstack_dashboard/dashboards/project/stacks/mappings.py +++ b/openstack_dashboard/dashboards/project/stacks/mappings.py @@ -14,6 +14,7 @@ import json import logging +import re import urlparse from django.core.urlresolvers import reverse @@ -81,3 +82,64 @@ def stack_output(output): if parts.netloc and parts.scheme in ('http', 'https'): return u'%s' % (output, output) return unicode(output) + + +resource_images = { + 'LB_FAILED': '/static/dashboard/img/lb-red.svg', + 'LB_DELETE': '/static/dashboard/img/lb-red.svg', + 'LB_IN_PROGRESS': '/static/dashboard/img/lb-gray.gif', + 'LB_COMPLETE': '/static/dashboard/img/lb-green.svg', + 'DB_FAILED': '/static/dashboard/img/db-red.svg', + 'DB_DELETE': '/static/dashboard/img/db-red.svg', + 'DB_IN_PROGRESS': '/static/dashboard/img/db-gray.gif', + 'DB_COMPLETE': '/static/dashboard/img/db-green.svg', + 'STACK_FAILED': '/static/dashboard/img/stack-red.svg', + 'STACK_DELETE': '/static/dashboard/img/stack-red.svg', + 'STACK_IN_PROGRESS': '/static/dashboard/img/stack-gray.gif', + 'STACK_COMPLETE': '/static/dashboard/img/stack-green.svg', + 'SERVER_FAILED': '/static/dashboard/img/server-red.svg', + 'SERVER_DELETE': '/static/dashboard/img/server-red.svg', + 'SERVER_IN_PROGRESS': '/static/dashboard/img/server-gray.gif', + 'SERVER_COMPLETE': '/static/dashboard/img/server-green.svg', + 'UNKNOWN_FAILED': '/static/dashboard/img/unknown-red.svg', + 'UNKNOWN_DELETE': '/static/dashboard/img/unknown-red.svg', + 'UNKNOWN_IN_PROGRESS': '/static/dashboard/img/unknown-gray.gif', + 'UNKNOWN_COMPLETE': '/static/dashboard/img/unknown-green.svg', +} + + +def get_resource_type(type): + if re.search('LoadBalancer', type): + return 'LB' + elif re.search('DBInstance', type): + return 'DB' + elif re.search('Instance', type): + return 'SERVER' + elif re.search('stack', type): + return 'STACK' + else: + return 'UNKNOWN' + + +def get_resource_status(status): + if re.search('IN_PROGRESS', status): + return 'IN_PROGRESS' + elif re.search('FAILED', status): + return 'FAILED' + elif re.search('DELETE', status): + return 'DELETE' + else: + return 'COMPLETE' + + +def get_resource_image(status, type): + ''' + Sets the image url and in_progress action sw based on status. + ''' + resource_type = get_resource_type(type) + resource_status = get_resource_status(status) + resource_state = resource_type + "_" + resource_status + + for key in resource_images: + if key == resource_state: + return resource_images.get(key) diff --git a/openstack_dashboard/dashboards/project/stacks/sro.py b/openstack_dashboard/dashboards/project/stacks/sro.py new file mode 100644 index 0000000000..f385ee556d --- /dev/null +++ b/openstack_dashboard/dashboards/project/stacks/sro.py @@ -0,0 +1,31 @@ +from django.template.defaultfilters import title +from django.template.loader import render_to_string + +from horizon.utils.filters import replace_underscores + + +def stack_info(stack, stack_image): + stack.stack_status_desc = title(replace_underscores(stack.stack_status)) + if stack.stack_status_reason: + stack.stack_status_reason = title( + replace_underscores(stack.stack_status_reason) + ) + context = {} + context['stack'] = stack + context['stack_image'] = stack_image + return render_to_string('project/stacks/_stack_info.html', + context) + + +def resource_info(resource): + resource.resource_status_desc = title( + replace_underscores(resource.resource_status) + ) + if resource.resource_status_reason: + resource.resource_status_reason = title( + replace_underscores(resource.resource_status_reason) + ) + context = {} + context['resource'] = resource + return render_to_string('project/stacks/_resource_info.html', + context) diff --git a/openstack_dashboard/dashboards/project/stacks/tabs.py b/openstack_dashboard/dashboards/project/stacks/tabs.py index c1adf35f3d..9a736bb21f 100644 --- a/openstack_dashboard/dashboards/project/stacks/tabs.py +++ b/openstack_dashboard/dashboards/project/stacks/tabs.py @@ -20,6 +20,7 @@ from horizon import messages from horizon import tabs from openstack_dashboard import api +from openstack_dashboard.dashboards.project.stacks.api import d3_data from openstack_dashboard.dashboards.project.stacks.tables import EventsTable from openstack_dashboard.dashboards.project.stacks.tables import ResourcesTable @@ -27,6 +28,20 @@ from openstack_dashboard.dashboards.project.stacks.tables import ResourcesTable LOG = logging.getLogger(__name__) +class StackTopologyTab(tabs.Tab): + name = _("Topology") + slug = "topology" + template_name = "project/stacks/_detail_topology.html" + preload = False + + def get_context_data(self, request): + context = {} + stack = self.tab_group.kwargs['stack'] + context['stack_id'] = stack.id + context['d3_data'] = d3_data(request, stack_id=stack.id) + return context + + class StackOverviewTab(tabs.Tab): name = _("Overview") slug = "overview" @@ -90,7 +105,8 @@ class StackResourcesTab(tabs.Tab): class StackDetailTabs(tabs.TabGroup): slug = "stack_details" - tabs = (StackOverviewTab, StackResourcesTab, StackEventsTab) + tabs = (StackTopologyTab, StackOverviewTab, StackResourcesTab, + StackEventsTab) sticky = True diff --git a/openstack_dashboard/dashboards/project/stacks/templates/stacks/_detail_topology.html b/openstack_dashboard/dashboards/project/stacks/templates/stacks/_detail_topology.html new file mode 100644 index 0000000000..d906ceadd9 --- /dev/null +++ b/openstack_dashboard/dashboards/project/stacks/templates/stacks/_detail_topology.html @@ -0,0 +1,9 @@ +{% load i18n sizeformat %} + +
+
+
+
+
+
+
\ No newline at end of file diff --git a/openstack_dashboard/dashboards/project/stacks/templates/stacks/_resource_info.html b/openstack_dashboard/dashboards/project/stacks/templates/stacks/_resource_info.html new file mode 100644 index 0000000000..05a92ec371 --- /dev/null +++ b/openstack_dashboard/dashboards/project/stacks/templates/stacks/_resource_info.html @@ -0,0 +1,10 @@ +

{{ resource.logical_resource_id }}

+ +{% if resource.resource_status == 'CREATE_FAILED' %} +

{{ resource.resource_status_desc }}

+

{{ resource.resource_status_reason }}

+{% else %} +

{{ resource.resource_status_desc }}

+{% endif %} + +

{{ resource.resource_type }}

\ No newline at end of file diff --git a/openstack_dashboard/dashboards/project/stacks/templates/stacks/_stack_info.html b/openstack_dashboard/dashboards/project/stacks/templates/stacks/_stack_info.html new file mode 100644 index 0000000000..3b548aa58d --- /dev/null +++ b/openstack_dashboard/dashboards/project/stacks/templates/stacks/_stack_info.html @@ -0,0 +1,16 @@ + +
+

{{ stack.stack_name }}

+

{{ stack.stack_status_desc }}

+
+
+{% if stack.stack_status == 'CREATE_FAILED' %} +

{{ stack.stack_status_reason }}

+{% else %} +

{{ stack.stack_status_desc }}

+{% endif %} +{% for output in stack.outputs %} + {% if output.output_key == 'WebsiteURL' %} + {{ output.description }} + {% endif %} +{% endfor %} \ No newline at end of file diff --git a/openstack_dashboard/dashboards/project/stacks/urls.py b/openstack_dashboard/dashboards/project/stacks/urls.py index 7271aeb30a..157f386097 100644 --- a/openstack_dashboard/dashboards/project/stacks/urls.py +++ b/openstack_dashboard/dashboards/project/stacks/urls.py @@ -15,6 +15,7 @@ from django.conf.urls.defaults import patterns from django.conf.urls.defaults import url +from openstack_dashboard.dashboards.project.stacks.api import get_d3_data from openstack_dashboard.dashboards.project.stacks.views import CreateStackView from openstack_dashboard.dashboards.project.stacks.views import DetailView from openstack_dashboard.dashboards.project.stacks.views import IndexView @@ -32,4 +33,7 @@ urlpatterns = patterns( url(r'^stack/(?P[^/]+)/$', DetailView.as_view(), name='detail'), url(r'^stack/(?P[^/]+)/(?P[^/]+)/$', ResourceView.as_view(), name='resource'), + + #AJAX urls + url(r'^get_d3_data/(?P[^/]+)/$', get_d3_data, name='d3_data') ) diff --git a/openstack_dashboard/dashboards/project/stacks/views.py b/openstack_dashboard/dashboards/project/stacks/views.py index 2beda10e94..97640dff33 100644 --- a/openstack_dashboard/dashboards/project/stacks/views.py +++ b/openstack_dashboard/dashboards/project/stacks/views.py @@ -102,6 +102,8 @@ class DetailView(tabs.TabView): try: stack = api.heat.stack_get(request, stack_id) self._stack = stack + request.session['stack_id'] = stack.id + request.session['stack_name'] = stack.stack_name except: msg = _("Unable to retrieve stack.") redirect = reverse('horizon:project:stacks:index') diff --git a/openstack_dashboard/static/dashboard/img/db-gray.gif b/openstack_dashboard/static/dashboard/img/db-gray.gif new file mode 100644 index 0000000000000000000000000000000000000000..7fbeb41af0659be9a0254bdfad52183f02095658 GIT binary patch literal 12495 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 + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openstack_dashboard/static/dashboard/img/db-green.svg b/openstack_dashboard/static/dashboard/img/db-green.svg new file mode 100644 index 0000000000..aea48b9d75 --- /dev/null +++ b/openstack_dashboard/static/dashboard/img/db-green.svg @@ -0,0 +1,85 @@ + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openstack_dashboard/static/dashboard/img/db-red.svg b/openstack_dashboard/static/dashboard/img/db-red.svg new file mode 100644 index 0000000000..9154fcd589 --- /dev/null +++ b/openstack_dashboard/static/dashboard/img/db-red.svg @@ -0,0 +1,85 @@ + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openstack_dashboard/static/dashboard/img/lb-gray.gif b/openstack_dashboard/static/dashboard/img/lb-gray.gif new file mode 100644 index 0000000000000000000000000000000000000000..9b1c51626450058f8d90153cbab53ba787bd2246 GIT binary patch literal 8447 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 + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openstack_dashboard/static/dashboard/img/lb-green.svg b/openstack_dashboard/static/dashboard/img/lb-green.svg new file mode 100644 index 0000000000..770ffc7986 --- /dev/null +++ b/openstack_dashboard/static/dashboard/img/lb-green.svg @@ -0,0 +1,43 @@ + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openstack_dashboard/static/dashboard/img/lb-red.svg b/openstack_dashboard/static/dashboard/img/lb-red.svg new file mode 100644 index 0000000000..12434fd1a7 --- /dev/null +++ b/openstack_dashboard/static/dashboard/img/lb-red.svg @@ -0,0 +1,43 @@ + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openstack_dashboard/static/dashboard/img/server-gray.gif b/openstack_dashboard/static/dashboard/img/server-gray.gif new file mode 100644 index 0000000000000000000000000000000000000000..7f411c0dd8da796113a7685ba211628593909422 GIT binary patch literal 7416 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 literal 0 HcmV?d00001 diff --git a/openstack_dashboard/static/dashboard/img/server-gray.svg b/openstack_dashboard/static/dashboard/img/server-gray.svg new file mode 100644 index 0000000000..9e17b0bdf3 --- /dev/null +++ b/openstack_dashboard/static/dashboard/img/server-gray.svg @@ -0,0 +1,50 @@ + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openstack_dashboard/static/dashboard/img/server-green.svg b/openstack_dashboard/static/dashboard/img/server-green.svg new file mode 100644 index 0000000000..52ac168ce9 --- /dev/null +++ b/openstack_dashboard/static/dashboard/img/server-green.svg @@ -0,0 +1,50 @@ + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openstack_dashboard/static/dashboard/img/server-red.svg b/openstack_dashboard/static/dashboard/img/server-red.svg new file mode 100644 index 0000000000..ecce52df92 --- /dev/null +++ b/openstack_dashboard/static/dashboard/img/server-red.svg @@ -0,0 +1,50 @@ + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openstack_dashboard/static/dashboard/img/stack-gray.gif b/openstack_dashboard/static/dashboard/img/stack-gray.gif new file mode 100644 index 0000000000000000000000000000000000000000..54a2cee4927185f16a3155b75268cfb4c36cfa08 GIT binary patch literal 14409 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 + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openstack_dashboard/static/dashboard/img/stack-green.svg b/openstack_dashboard/static/dashboard/img/stack-green.svg new file mode 100644 index 0000000000..3faac892f6 --- /dev/null +++ b/openstack_dashboard/static/dashboard/img/stack-green.svg @@ -0,0 +1,82 @@ + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openstack_dashboard/static/dashboard/img/stack-red.svg b/openstack_dashboard/static/dashboard/img/stack-red.svg new file mode 100644 index 0000000000..14bf3cd847 --- /dev/null +++ b/openstack_dashboard/static/dashboard/img/stack-red.svg @@ -0,0 +1,92 @@ + + + + +Compute + + + + + + + + + + + + + + + + + + + + Compute + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Load Balancer + + + + + + + + + + + + + + + + + + + + diff --git a/openstack_dashboard/static/dashboard/img/unknown-gray.gif b/openstack_dashboard/static/dashboard/img/unknown-gray.gif new file mode 100644 index 0000000000000000000000000000000000000000..c90d8d8aa5e427d5ae69b6f291a07c1afc2c5bdf GIT binary patch literal 10805 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 + + +]> + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openstack_dashboard/static/dashboard/img/unknown-red.svg b/openstack_dashboard/static/dashboard/img/unknown-red.svg new file mode 100644 index 0000000000..90fd38dbb7 --- /dev/null +++ b/openstack_dashboard/static/dashboard/img/unknown-red.svg @@ -0,0 +1,33 @@ + + + +]> + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openstack_dashboard/static/dashboard/less/horizon.less b/openstack_dashboard/static/dashboard/less/horizon.less index f62f6233f0..9d6fa717d6 100644 --- a/openstack_dashboard/static/dashboard/less/horizon.less +++ b/openstack_dashboard/static/dashboard/less/horizon.less @@ -2085,5 +2085,21 @@ div.network { } } +/**** Resource Topology CSS ****/ +.link {stroke: #000;stroke-width: 1.5px;} +.node {cursor:pointer;} +.node text {font: 12px sans-serif;} +#resource_container {position:relative;} +#stack_box {position:absolute;width:300px;top:10px;left:10px;} +#stack_box h3 {font-size:11pt;line-height:20px;} +#stack_box p {margin:0;font-size:9pt;line-height:14px;} +#stack_box a {margin:0;font-size:9pt;line-height:14px;} +#stack_box img {float:left;} +#stack_box #stack_info {float:left;white-space:normal;width:200px;} +#info_box {position:absolute;width:300px;top:100px;left:10px;} +#info_box h3 {font-size:9pt;line-height:20px;} +#info_box p {margin:0;font-size:9pt;line-height:14px;} +#info_box a {margin:0;font-size:9pt;line-height:14px;} +#info_box .error {color:darkred;}