From 2fd75cf7cb7fd9e53e32e57d649f6aa11652fa3a Mon Sep 17 00:00:00 2001 From: Ari Zellner Date: Mon, 9 Jan 2017 18:59:45 +0200 Subject: [PATCH] topology for container projects --- .../container_topology_controller.js | 11 +++- .../container_project_topology_controller.rb | 6 ++ app/controllers/mixins/generic_show_mixin.rb | 2 + app/controllers/mixins/more_show_actions.rb | 6 ++ .../application_helper/page_layouts.rb | 3 +- .../toolbar/container_project_view.rb | 21 +++++++ .../application_helper/toolbar_chooser.rb | 2 + .../container_project_topology_service.rb | 38 +++++++++++ app/services/container_topology_service.rb | 63 +------------------ .../container_topology_service_mixin.rb | 63 +++++++++++++++++++ app/views/container_project/show.html.haml | 2 + config/routes.rb | 7 +++ 12 files changed, 159 insertions(+), 65 deletions(-) create mode 100644 app/controllers/container_project_topology_controller.rb create mode 100644 app/helpers/application_helper/toolbar/container_project_view.rb create mode 100644 app/services/container_project_topology_service.rb create mode 100644 app/services/container_topology_service_mixin.rb diff --git a/app/assets/javascripts/controllers/container_topology/container_topology_controller.js b/app/assets/javascripts/controllers/container_topology/container_topology_controller.js index ddc40f613b88..79d1f4bd8ebc 100644 --- a/app/assets/javascripts/controllers/container_topology/container_topology_controller.js +++ b/app/assets/javascripts/controllers/container_topology/container_topology_controller.js @@ -16,16 +16,21 @@ function ContainerTopologyCtrl($scope, $http, $interval, topologyService, $windo $scope.d3 = d3; $scope.refresh = function() { - var id; + var id, type; var pathname = $window.location.pathname.replace(/\/$/, ''); if (pathname.match(/show$/)) { id = ''; + } else if (pathname.match('/(.+)/show/([0-9]+)')) { + var arr = pathname.match('/(.+)/show/([0-9]+)') + type = arr[1] + '_topology' + id = '/' + arr[2] } else { // search for pattern ^//$ in the pathname + type = 'container_topology' id = '/' + (/^\/[^\/]+\/(\d+)$/.exec(pathname)[1]); } - var url = '/container_topology/data' + id; + var url = '/' + type + '/data' + id; $http.get(url) .then(getContainerTopologyData) @@ -254,6 +259,8 @@ function ContainerTopologyCtrl($scope, $http, $interval, topologyService, $windo switch (d.item.kind) { case "ContainerManager": return { x: -20, y: -20, r: 28 }; + case "ContainerProject": + return { x: defaultDimensions.x, y: defaultDimensions.y, r: 28 }; case "Container": return { x: 1, y: 5, r: 13 }; case "ContainerGroup": diff --git a/app/controllers/container_project_topology_controller.rb b/app/controllers/container_project_topology_controller.rb new file mode 100644 index 000000000000..88916377826b --- /dev/null +++ b/app/controllers/container_project_topology_controller.rb @@ -0,0 +1,6 @@ +class ContainerProjectTopologyController < TopologyController + @layout = "container_topology" + @service_class = ContainerProjectTopologyService + + menu_section :cnt +end diff --git a/app/controllers/mixins/generic_show_mixin.rb b/app/controllers/mixins/generic_show_mixin.rb index e4e0209de5b3..56a70cbe6d32 100644 --- a/app/controllers/mixins/generic_show_mixin.rb +++ b/app/controllers/mixins/generic_show_mixin.rb @@ -17,6 +17,8 @@ def show show_performance if respond_to?(:performance) when "compliance_history" show_compliance_history if respond_to?(:compliance_history) + when "topology" + show_topology # nested list methods as enabled by 'display_methods' when *self.class.display_methods diff --git a/app/controllers/mixins/more_show_actions.rb b/app/controllers/mixins/more_show_actions.rb index 30b6d82dd9f6..9f2dfe3e85ce 100644 --- a/app/controllers/mixins/more_show_actions.rb +++ b/app/controllers/mixins/more_show_actions.rb @@ -27,6 +27,12 @@ def show_compliance_history @showtype = @display end + def show_topology + @showtype = "topology" + drop_breadcrumb(:name => @record.name + _(" (Topology)"), + :url => "/#{controller_name}/show/#{@record.id}?display=topology") + end + def update_session_for_compliance_history(count) @ch_tree = TreeBuilderComplianceHistory.new(:ch_tree, :ch, @sb, true, @record) session[:ch_tree] = @ch_tree.tree_nodes diff --git a/app/helpers/application_helper/page_layouts.rb b/app/helpers/application_helper/page_layouts.rb index cbe034ef132b..33eac78fa81e 100644 --- a/app/helpers/application_helper/page_layouts.rb +++ b/app/helpers/application_helper/page_layouts.rb @@ -73,7 +73,8 @@ def layout_uses_tabs? (@layout == "report" && ["new", "create", "edit", "copy", "update", "explorer"].include?(controller.action_name)) return false elsif %w(container_dashboard dashboard ems_infra_dashboard).include?(@layout) || - (%w(dashboard topology).include?(@showtype) && @lastaction.ends_with?("_dashboard")) + (%w(dashboard).include?(@showtype) && @lastaction.ends_with?("_dashboard")) || + %w(topology).include?(@showtype) # Dashboard tabs are located in taskbar because they are otherwise hidden behind the taskbar regardless of z-index return false end diff --git a/app/helpers/application_helper/toolbar/container_project_view.rb b/app/helpers/application_helper/toolbar/container_project_view.rb new file mode 100644 index 000000000000..20cf2e174cdf --- /dev/null +++ b/app/helpers/application_helper/toolbar/container_project_view.rb @@ -0,0 +1,21 @@ +class ApplicationHelper::Toolbar::ContainerProjectView < ApplicationHelper::Toolbar::Basic + button_group('container_project', [ + twostate( + :view_summary, + 'fa fa-th-list', + N_('Summary View'), + nil, + :url => "/show", + :url_parms => "" + ), + twostate( + :view_topology, + 'fa pficon-topology', + N_('Topology View'), + nil, + :url => "/show", + :url_parms => "?display=topology", + :klass => ApplicationHelper::Button::TopologyFeatureButton + ) + ]) +end diff --git a/app/helpers/application_helper/toolbar_chooser.rb b/app/helpers/application_helper/toolbar_chooser.rb index bf4d4be78a20..43aef36da9b5 100644 --- a/app/helpers/application_helper/toolbar_chooser.rb +++ b/app/helpers/application_helper/toolbar_chooser.rb @@ -43,6 +43,8 @@ def view_toolbar_filename 'drift_view_tb' elsif %w(ems_container ems_infra).include?(@layout) && %w(main dashboard topology).include?(@display) 'dashboard_summary_toggle_view_tb' + elsif %w(container_project).include?(@layout) + "#{@layout}_view_tb" elsif !%w(all_tasks all_ui_tasks timeline diagnostics my_tasks my_ui_tasks miq_server usage).include?(@layout) && (!@layout.starts_with?("miq_request")) && !@treesize_buttons && @display == "main" && @showtype == "main" && !@in_a_form diff --git a/app/services/container_project_topology_service.rb b/app/services/container_project_topology_service.rb new file mode 100644 index 000000000000..bb1bf0092bc8 --- /dev/null +++ b/app/services/container_project_topology_service.rb @@ -0,0 +1,38 @@ +class ContainerProjectTopologyService < TopologyService + include UiServiceMixin + include ContainerTopologyServiceMixin + + @provider_class = ContainerProject + + def build_topology + topo_items = {} + links = [] + + entity_relationships = { :ContainerProject => { :ContainerGroups => { + :Containers => nil, + :ContainerReplicator => nil, + :ContainerServices => { :ContainerRoutes => nil }, + :ContainerNode => { :lives_on => {:Host => nil}} + } + } + } + + preloaded = @providers.includes(:container_groups => [:containers, + :container_replicator, + :container_node => [:lives_on => [:host]], + :container_services => [:container_routes]]) + + preloaded.each do |entity| + topo_items, links = build_recursive_topology(entity, entity_relationships[:ContainerProject], topo_items, links) + end + + populate_topology(topo_items, links, build_kinds, icons) + end + + + def build_kinds + kinds = [:ContainerReplicator, :ContainerGroup, :Container, :ContainerNode, + :ContainerService, :Host, :Vm, :ContainerRoute, :ContainerManager, :ContainerProject] + build_legend_kinds(kinds) + end +end diff --git a/app/services/container_topology_service.rb b/app/services/container_topology_service.rb index ffc64f5b2e5c..620428ebf135 100644 --- a/app/services/container_topology_service.rb +++ b/app/services/container_topology_service.rb @@ -1,5 +1,6 @@ class ContainerTopologyService < TopologyService include UiServiceMixin + include ContainerTopologyServiceMixin @provider_class = ManageIQ::Providers::ContainerManager @@ -22,68 +23,6 @@ def build_topology populate_topology(topo_items, links, build_kinds, icons) end - def entity_display_type(entity) - if entity.kind_of?(ManageIQ::Providers::ContainerManager) - entity.class.short_token - elsif entity.kind_of?(ContainerGroup) - "Pod" - else - name = entity.class.name.demodulize - if name.start_with? "Container" - if name.length > "Container".length # container related entities such as ContainerService - name["Container".length..-1] - else - "Container" # the container entity itself - end - else - if entity.kind_of?(Vm) - name.upcase # turn Vm to VM because it's an abbreviation - else - name # non container entities such as Host - end - end - end - end - - def build_entity_data(entity) - data = build_base_entity_data(entity) - data.merge!(:status => entity_status(entity), - :display_kind => entity_display_type(entity)) - - if (entity.kind_of?(Host) || entity.kind_of?(Vm)) && entity.ext_management_system.present? - data.merge!(:provider => entity.ext_management_system.name) - end - - data - end - - def entity_status(entity) - if entity.kind_of?(Host) || entity.kind_of?(Vm) - status = entity.power_state.capitalize - elsif entity.kind_of?(ContainerNode) - node_ready_status = entity.container_conditions.find_by_name('Ready').try(:status) - status = case node_ready_status - when 'True' - 'Ready' - when 'False' - 'NotReady' - else - 'Unknown' - end - elsif entity.kind_of?(ContainerGroup) - status = entity.phase - elsif entity.kind_of?(Container) - status = entity.state.capitalize - elsif entity.kind_of?(ContainerReplicator) - status = (entity.current_replicas == entity.replicas) ? 'OK' : 'Warning' - elsif entity.kind_of?(ManageIQ::Providers::ContainerManager) - status = entity.authentications.empty? ? 'Unknown' : entity.default_authentication.status.capitalize - else - status = 'Unknown' - end - status - end - def build_kinds kinds = [:ContainerReplicator, :ContainerGroup, :Container, :ContainerNode, :ContainerService, :Host, :Vm, :ContainerRoute, :ContainerManager] diff --git a/app/services/container_topology_service_mixin.rb b/app/services/container_topology_service_mixin.rb new file mode 100644 index 000000000000..d12e25dab93f --- /dev/null +++ b/app/services/container_topology_service_mixin.rb @@ -0,0 +1,63 @@ +module ContainerTopologyServiceMixin + def entity_display_type(entity) + if entity.kind_of?(ManageIQ::Providers::ContainerManager) + entity.class.short_token + elsif entity.kind_of?(ContainerGroup) + "Pod" + else + name = entity.class.name.demodulize + if name.start_with? "Container" + if name.length > "Container".length # container related entities such as ContainerService + name["Container".length..-1] + else + "Container" # the container entity itself + end + else + if entity.kind_of?(Vm) + name.upcase # turn Vm to VM because it's an abbreviation + else + name # non container entities such as Host + end + end + end + end + + def build_entity_data(entity) + data = build_base_entity_data(entity) + data.merge!(:status => entity_status(entity), + :display_kind => entity_display_type(entity)) + + if (entity.kind_of?(Host) || entity.kind_of?(Vm)) && entity.ext_management_system.present? + data.merge!(:provider => entity.ext_management_system.name) + end + + data + end + + def entity_status(entity) + if entity.kind_of?(Host) || entity.kind_of?(Vm) + status = entity.power_state.capitalize + elsif entity.kind_of?(ContainerNode) + node_ready_status = entity.container_conditions.find_by_name('Ready').try(:status) + status = case node_ready_status + when 'True' + 'Ready' + when 'False' + 'NotReady' + else + 'Unknown' + end + elsif entity.kind_of?(ContainerGroup) + status = entity.phase + elsif entity.kind_of?(Container) + status = entity.state.capitalize + elsif entity.kind_of?(ContainerReplicator) + status = (entity.current_replicas == entity.replicas) ? 'OK' : 'Warning' + elsif entity.kind_of?(ManageIQ::Providers::ContainerManager) + status = entity.authentications.empty? ? 'Unknown' : entity.default_authentication.status.capitalize + else + status = 'Unknown' + end + status + end +end diff --git a/app/views/container_project/show.html.haml b/app/views/container_project/show.html.haml index 6c05f83d1e2c..8327599f0b1a 100644 --- a/app/views/container_project/show.html.haml +++ b/app/views/container_project/show.html.haml @@ -6,3 +6,5 @@ = render :partial => "layouts/performance_async" - elsif @showtype == "main" = render :partial => "layouts/textual_groups_generic" +- elsif @showtype == "topology" + = render :file => 'container_topology/show' diff --git a/config/routes.rb b/config/routes.rb index 02bb619ba38d..8f273b5be35e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -983,6 +983,13 @@ ) }, + :container_project_topology => { + :get => %w( + show + data + ) + }, + :middleware_topology => { :get => %w( show