diff --git a/app/assets/images/100/healthstate-normal.png b/app/assets/images/100/healthstate-normal.png new file mode 100644 index 00000000000..9a7897938b8 Binary files /dev/null and b/app/assets/images/100/healthstate-normal.png differ diff --git a/app/assets/images/svg/healthstate-critical.svg b/app/assets/images/svg/healthstate-critical.svg new file mode 100644 index 00000000000..15d0ebfc39d --- /dev/null +++ b/app/assets/images/svg/healthstate-critical.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/app/assets/images/svg/healthstate-unknown.svg b/app/assets/images/svg/healthstate-unknown.svg new file mode 100644 index 00000000000..56b69acc62c --- /dev/null +++ b/app/assets/images/svg/healthstate-unknown.svg @@ -0,0 +1,13 @@ + + + + + diff --git a/app/controllers/application_controller/ci_processing.rb b/app/controllers/application_controller/ci_processing.rb index 200319b6eb6..e59e805e3ab 100644 --- a/app/controllers/application_controller/ci_processing.rb +++ b/app/controllers/application_controller/ci_processing.rb @@ -2508,6 +2508,18 @@ def providehosts host_button_operation('provide', _('Provide')) end + def refreshphysicalservers + # TODO: refresh physical servers + end + + def deletephysicalservers + # TODO: delete physical servers + end + + def editphysicalservers + # TODO: edit physical servers + end + # Handle the Host power buttons POWER_BUTTON_NAMES = { "reboot" => _("Restart"), diff --git a/app/controllers/ems_common.rb b/app/controllers/ems_common.rb index eadceb05bca..ea8e42ae77b 100644 --- a/app/controllers/ems_common.rb +++ b/app/controllers/ems_common.rb @@ -53,6 +53,68 @@ def show_ad_hoc_metrics drop_breadcrumb(:name => @ems.name + _(" (Ad hoc Metrics)"), :url => show_link(@ems)) end + def show_topology + @showtype = "topology" + @lastaction = "show_topology" + drop_breadcrumb(:name => @ems.name + _(" (Topology)"), :url => show_link(@ems)) + end + + def view_setup_params + { + "instances" => [ManageIQ::Providers::CloudManager::Vm, _("Instances")], + "images" => [ManageIQ::Providers::CloudManager::Template, _("Images")], + "block_storage_managers" => [ManageIQ::Providers::StorageManager, + _("Block Storage Managers"), + :block_storage_managers], + "object_storage_managers" => [ManageIQ::Providers::StorageManager, + _("Object Storage Managers"), + :object_storage_managers], + "storage_managers" => [ManageIQ::Providers::StorageManager, + _("Storage Managers"), + :storage_managers], + "miq_templates" => [MiqTemplate, _("Templates")], + "vms" => [Vm, _("VMs")], + "orchestration_stacks" => [OrchestrationStack, _("Stacks")], + # "configuration_jobs" => [ConfigurationJob, _("Configuration Jobs")], + "cloud_object_store_containers" => [CloudObjectStoreContainer, _('Cloud Object Store Containers')], + 'containers' => [Container, _('Containers')], + 'container_replicators' => [ContainerReplicator, _('Container Replicators')], + 'container_nodes' => [ContainerNode, _('Container Nodes')], + 'container_groups' => [ContainerGroup, _('Pods')], + 'container_services' => [ContainerService, _('Container Services')], + 'container_images' => [ContainerImage, _('Container Images')], + 'container_routes' => [ContainerRoute, _('Container Routes')], + 'container_builds' => [ContainerBuild, _('Container Builds')], + 'container_projects' => [ContainerProject, _('Container Projects')], + 'container_image_registries' => [ContainerImageRegistry, _('Container Image Registries')], + 'container_templates' => [ContainerTemplate, _('Container Templates')], + 'availability_zones' => [AvailabilityZone, _('Availability Zones')], + 'host_aggregates' => [HostAggregate, _('Host Aggregates')], + 'middleware_servers' => [MiddlewareServer, _('Middleware Servers')], + 'middleware_deployments' => [MiddlewareDeployment, _('Middleware Deployments')], + 'middleware_datasources' => [MiddlewareDatasource, _('Middleware Datasources')], + 'middleware_domains' => [MiddlewareDomain, _('Middleware Domains')], + 'middleware_server_groups' => [MiddlewareServerGroup, _('Middleware Server Groups')], + 'middleware_messagings' => [MiddlewareMessaging, _('Middleware Messagings')], + 'cloud_tenants' => [CloudTenant, _('Cloud Tenants')], + 'cloud_volumes' => [CloudVolume, _('Cloud Volumes')], + 'cloud_volume_snapshots' => [CloudVolumeSnapshot, _('Cloud Volume Snapshots')], + 'flavors' => [Flavor, _('Flavors')], + 'security_groups' => [SecurityGroup, _('Security Groups')], + 'floating_ips' => [FloatingIp, _('Floating IPs')], + 'network_routers' => [NetworkRouter, _('Network Routers')], + 'network_ports' => [NetworkPort, _('Network Ports')], + 'cloud_subnets' => [CloudSubnet, _('Cloud Subnets')], + 'cloud_networks' => [CloudNetwork, _('Cloud Networks')], + 'load_balancers' => [LoadBalancer, _('Load Balancers')], + 'storages' => [Storage, _('Managed Datastores')], + 'ems_clusters' => [EmsCluster, title_for_clusters], + 'persistent_volumes' => [PersistentVolume, _('Volumes'), :persistent_volumes], + 'hosts' => [Host, _("Managed Hosts")], + 'physical_servers' => [PhysicalServer, _("Physical Servers")], + } + end + def display_block_storage_managers nested_list('block_storage_manager', ManageIQ::Providers::StorageManager, :parent_method => :block_storage_managers) end @@ -335,6 +397,10 @@ def button when "network_router_tag" then tag(NetworkRouter) when "orchestration_stack_tag" then tag(OrchestrationStack) when "security_group_tag" then tag(SecurityGroup) + # Physical server + when "physical_server_refresh" then refreshphysicalservers + when "physical_server_delete" then deletephysicalservers + when "physical_server_edit" then editphysicalservers end pfx = pfx_for_vm_button_pressed(params[:pressed]) @@ -707,6 +773,13 @@ def form_instance_vars @hawkular_security_protocols = retrieve_hawkular_security_protocols end + def retrieve_hawkular_security_protocols + [[_('SSL'), 'ssl-with-validation'], + [_('SSL trusting custom CA'), 'ssl-with-validation-custom-ca'], + [_('SSL without validation'), 'ssl-without-validation'], + [_('Non-SSL'), 'non-ssl']] + end + def retrieve_provider_regions managers = model.supported_subclasses.select(&:supports_regions?) managers.each_with_object({}) do |manager, provider_regions| @@ -757,13 +830,6 @@ def retrieve_container_security_protocols [_('SSL without validation'), 'ssl-without-validation']] end - def retrieve_hawkular_security_protocols - [[_('SSL'), 'ssl-with-validation'], - [_('SSL trusting custom CA'), 'ssl-with-validation-custom-ca'], - [_('SSL without validation'), 'ssl-without-validation'], - [_('Non-SSL'), 'non-ssl']] - end - # Get variables from edit form def get_form_vars @ems = @edit[:ems_id] ? model.find_by_id(@edit[:ems_id]) : model.new diff --git a/app/controllers/physical_server_controller.rb b/app/controllers/physical_server_controller.rb new file mode 100644 index 00000000000..21f6828c8e6 --- /dev/null +++ b/app/controllers/physical_server_controller.rb @@ -0,0 +1,117 @@ +class PhysicalServerController < ApplicationController + include Mixins::GenericListMixin + include Mixins::GenericShowMixin + + before_action :check_privileges + before_action :session_data + after_action :cleanup_action + after_action :set_session_data + + def self.table_name + @table_name ||= "physical_servers" + end + + def session_data + @title = _("Physical Servers") + @layout = "physical_server" + @lastaction = session[:physical_server_lastaction] + end + + def collect_data(server_id) + PhysicalServerService.new(server_id, self).all_data + end + + def set_session_data + session[:layout] = @layout + session[:physical_server_lastaction] = @lastaction + end + + def show_list + # Disable the cache to prevent a caching problem that occurs when + # pressing the browser's back arrow button to return to the show_list + # page while on the Physical Server's show page. Disabling the cache + # causes the page and its session variables to actually be reloaded. + disable_client_cache + + process_show_list + end + + # Handles buttons pressed on the toolbar + def button + # Get the list of servers to apply the action to + servers = retrieve_servers + + # Apply the action (depending on the button pressed) to the servers + apply_action_to_servers(servers) + end + + private + + # Maps button actions to actual method names to be called and the + # corresponding result status messages to be displayed + ACTIONS = {"physical_server_power_on" => [:power_on, "Power On"], + "physical_server_power_off" => [:power_off, "Power Off"], + "physical_server_restart" => [:restart, "Restart"], + "physical_server_blink_loc_led" => [:blink_loc_led, "Blink LED"], + "physical_server_turn_on_loc_led" => [:turn_on_loc_led, "Turn On LED"], + "physical_server_turn_off_loc_led" => [:turn_off_loc_led, "Turn Off LED"]}.freeze + + # Displays an error message + def display_error_message(msg) + display_message(msg, :error) + end + + # Displays a success message + def display_success_message(msg) + display_message(msg, :success) + end + + # Displays a message + def display_message(msg, level) + add_flash(_(msg), level) + render_flash + end + + # Returns a list of servers to which the button action will be applied + def retrieve_servers + server_id = params[:id] + servers = [] + + # A list of servers + if @lastaction == "show_list" + server_ids = find_checked_items + server_ids.each do |id| + servers.push(PhysicalServer.find_by('id' => id)) + end + if server_ids.empty? + display_error_message("No server IDs found for the selected servers") + end + # A single server + elsif server_id.nil? || PhysicalServer.find_by('id' => server_id).nil? + display_error_message("No server ID found for the current server") + else + servers.push(PhysicalServer.find_by('id' => server_id)) + end + + servers + end + + # Applies the appropriate action to a list of servers depending + # on the button pressed + def apply_action_to_servers(servers) + button_pressed = params[:pressed] + + # Apply the appropriate action to each server + if ACTIONS.key?(button_pressed) + method = ACTIONS[button_pressed][0] + action_str = ACTIONS[button_pressed][1] + servers.each do |server| + server.send(method) + end + msg = "Successfully initiated the #{action_str} action" + display_success_message(msg) + else + display_error_message("Unknown action: #{button_pressed}") + end + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index aa2c432a267..4b9cf72e190 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1221,6 +1221,7 @@ def pdf_page_size_style offline orchestration_stack physical_infra_topology + physical_server persistent_volume policy policy_group @@ -1313,6 +1314,7 @@ def render_listnav_filename offline orchestration_stack persistent_volume + physical_server resource_pool retired security_group @@ -1381,6 +1383,7 @@ def render_listnav_filename network_router orchestration_stack persistent_volume + physical_server policy resource_pool scan_profile @@ -1457,6 +1460,8 @@ def db_for_quadicon case @layout when "ems_infra" :ems + when "ems_physical_infra" + :ems when "ems_cloud" :ems_cloud else diff --git a/app/helpers/application_helper/button/physical_server_feature_button.rb b/app/helpers/application_helper/button/physical_server_feature_button.rb new file mode 100644 index 00000000000..cbabb07c4e6 --- /dev/null +++ b/app/helpers/application_helper/button/physical_server_feature_button.rb @@ -0,0 +1,9 @@ +class ApplicationHelper::Button::PhysicalServerFeatureButton < ApplicationHelper::Button::GenericFeatureButton + def visible? + true + end + + def disabled? + false + end +end diff --git a/app/helpers/application_helper/button/physical_server_feature_button_with_disable.rb b/app/helpers/application_helper/button/physical_server_feature_button_with_disable.rb new file mode 100644 index 00000000000..2e7b04460b1 --- /dev/null +++ b/app/helpers/application_helper/button/physical_server_feature_button_with_disable.rb @@ -0,0 +1,9 @@ +class ApplicationHelper::Button::PhysicalServerFeatureButtonWithDisable < ApplicationHelper::Button::GenericFeatureButtonWithDisable + def visible? + true + end + + def disabled? + false + end +end diff --git a/app/helpers/application_helper/toolbar/physical_server_center.rb b/app/helpers/application_helper/toolbar/physical_server_center.rb new file mode 100644 index 00000000000..5d9c6384238 --- /dev/null +++ b/app/helpers/application_helper/toolbar/physical_server_center.rb @@ -0,0 +1,131 @@ +class ApplicationHelper::Toolbar::PhysicalServerCenter < ApplicationHelper::Toolbar::Basic + button_group( + 'physical_server_vmdb', + [ + select( + :physical_server_vmdb_choice, + 'fa fa-cog fa-lg', + t = N_('Configuration'), + t, + :items => [ + button( + :physical_server_refresh, + 'fa fa-refresh fa-lg', + N_('Refresh relationships and power states for all items related to the selected items'), + N_('Refresh Relationships and Power States'), + :url_parms => "main_div", + :confirm => N_("Refresh relationships and power states for all items related to the selected items?"), + :enabled => false, + :onwhen => "1+" + ), + button( + :physical_server_edit, + 'pficon pficon-edit fa-lg', + t = N_('Edit Selected items'), + t, + :url_parms => "main_div", + :enabled => false, + :onwhen => "1+" + ), + button( + :physical_server_delete, + 'pficon pficon-delete fa-lg', + N_('Remove Selected items'), + N_('Remove items'), + :url_parms => "main_div", + :confirm => N_("Warning: The selected items and ALL of their components will be permanently removed!?"), + :enabled => false, + :onwhen => "1+" + ), + ] + ), + ] + ) + button_group( + 'physical_server_operations', + [ + select( + :physical_server_power_choice, + 'fa fa-power-off fa-lg', + N_('Power Operations'), + N_('Power'), + :items => [ + button( + :physical_server_power_on, + nil, + N_('Power on the server'), + N_('Power On'), + :image => "power_on", + :url_parms => "main_div", + :confirm => N_("Power on the server?"), + :klass => ApplicationHelper::Button::PhysicalServerFeatureButton, + :options => {:feature => :power_on} + ), + button( + :physical_server_power_off, + nil, + N_('Power off the server'), + N_('Power Off'), + :image => "power_off", + :url_parms => "main_div", + :confirm => N_("Power off the server?"), + :klass => ApplicationHelper::Button::PhysicalServerFeatureButton, + :options => {:feature => :power_off} + ), + button( + :physical_server_restart, + nil, + N_('Restart the server'), + N_('Restart'), + :image => "power_reset", + :url_parms => "main_div", + :confirm => N_("Restart the server?"), + :klass => ApplicationHelper::Button::PhysicalServerFeatureButton, + :options => {:feature => :restart} + ), + ] + ), + select( + :physical_server_identify_choice, + nil, + N_('Identify LED Operations'), + N_('Identify'), + :items => [ + button( + :physical_server_blink_loc_led, + nil, + N_('Blink the Identify LED'), + N_('Blink LED'), + :image => "blank_button", + :url_parms => "main_div", + :confirm => N_("Blink the Identify LED?"), + :klass => ApplicationHelper::Button::PhysicalServerFeatureButton, + :options => {:feature => :blink_loc_led} + ), + button( + :physical_server_turn_on_loc_led, + nil, + N_('Turn on the Idenfity LED'), + N_('Turn On LED'), + :image => "blank_button", + :url_parms => "main_div", + :confirm => N_("Turn on the Identify LED?"), + :klass => ApplicationHelper::Button::PhysicalServerFeatureButton, + :options => {:feature => :turn_on_loc_led} + ), + button( + :physical_server_turn_off_loc_led, + nil, + N_('Turn off the Identify LED'), + N_('Turn Off LED'), + :image => "blank_button", + :url_parms => "main_div", + :confirm => N_("Turn off the Identify LED?"), + :klass => ApplicationHelper::Button::PhysicalServerFeatureButton, + :options => {:feature => :turn_off_loc_led} + ), + ] + ), + ] + ) +end diff --git a/app/helpers/application_helper/toolbar/physical_servers_center.rb b/app/helpers/application_helper/toolbar/physical_servers_center.rb new file mode 100644 index 00000000000..4e508f6a2c2 --- /dev/null +++ b/app/helpers/application_helper/toolbar/physical_servers_center.rb @@ -0,0 +1,135 @@ +class ApplicationHelper::Toolbar::PhysicalServersCenter < ApplicationHelper::Toolbar::Basic + button_group( + 'physical_server_vmdb', + [ + select( + :physical_server_vmdb_choice, + 'fa fa-cog fa-lg', + t = N_('Configuration'), + t, + :items => [ + button( + :physical_server_refresh, + 'fa fa-refresh fa-lg', + N_('Refresh relationships and power states for all items related to the selected items'), + N_('Refresh Relationships and Power States'), + :url_parms => "main_div", + :confirm => N_("Refresh relationships and power states for all items related to the selected items?"), + :enabled => false, + :onwhen => "1+" + ), + button( + :physical_server_edit, + 'pficon pficon-edit fa-lg', + t = N_('Edit Selected items'), + t, + :url_parms => "main_div", + :enabled => false, + :onwhen => "1+" + ), + button( + :physical_server_delete, + 'pficon pficon-delete fa-lg', + N_('Remove Selected items'), + N_('Remove items'), + :url_parms => "main_div", + :confirm => N_("Warning: The selected items and ALL of their components will be permanently removed!?"), + :enabled => false, + :onwhen => "1+" + ), + ] + ), + ] + ) + button_group( + 'physical_server_operations', + [ + select( + :physical_server_power_choice, + 'fa fa-power-off fa-lg', + N_('Power Operations'), + N_('Power'), + :enabled => false, + :onwhen => "1+", + :items => [ + button( + :physical_server_power_on, + nil, + N_('Power on the server'), + N_('Power On'), + :image => "power_on", + :url_parms => "main_div", + :confirm => N_("Power on the server?"), + :klass => ApplicationHelper::Button::PhysicalServerFeatureButton, + :options => {:feature => :power_on} + ), + button( + :physical_server_power_off, + nil, + N_('Power off the server'), + N_('Power Off'), + :image => "power_off", + :url_parms => "main_div", + :confirm => N_("Power off the server?"), + :klass => ApplicationHelper::Button::PhysicalServerFeatureButton, + :options => {:feature => :power_off} + ), + button( + :physical_server_restart, + nil, + N_('Restart the server'), + N_('Restart'), + :image => "power_reset", + :url_parms => "main_div", + :confirm => N_("Restart the server?"), + :klass => ApplicationHelper::Button::PhysicalServerFeatureButton, + :options => {:feature => :restart} + ), + ] + ), + select( + :physical_server_identify_choice, + nil, + N_('Identify LED Operations'), + N_('Identify'), + :enabled => false, + :onwhen => "1+", + :items => [ + button( + :physical_server_blink_loc_led, + nil, + N_('Blink the Identify LED'), + N_('Blink LED'), + :image => "blank_button", + :url_parms => "main_div", + :confirm => N_("Blink the Identify LED?"), + :klass => ApplicationHelper::Button::PhysicalServerFeatureButton, + :options => {:feature => :blink_loc_led} + ), + button( + :physical_server_turn_on_loc_led, + nil, + N_('Turn on the Idenfity LED'), + N_('Turn On LED'), + :image => "blank_button", + :url_parms => "main_div", + :confirm => N_("Turn on the Identify LED?"), + :klass => ApplicationHelper::Button::PhysicalServerFeatureButton, + :options => {:feature => :turn_on_loc_led} + ), + button( + :physical_server_turn_off_loc_led, + nil, + N_('Turn off the Identify LED'), + N_('Turn Off LED'), + :image => "blank_button", + :url_parms => "main_div", + :confirm => N_("Turn off the Identify LED?"), + :klass => ApplicationHelper::Button::PhysicalServerFeatureButton, + :options => {:feature => :turn_off_loc_led} + ), + ] + ), + ] + ) +end diff --git a/app/helpers/application_helper/toolbar_chooser.rb b/app/helpers/application_helper/toolbar_chooser.rb index e61a53198c0..91c1982054e 100644 --- a/app/helpers/application_helper/toolbar_chooser.rb +++ b/app/helpers/application_helper/toolbar_chooser.rb @@ -527,6 +527,7 @@ def center_toolbar_filename_classic middleware_messaging orchestration_stack physical_infra_topology + physical_server resource_pool storage_manager container_template diff --git a/app/helpers/ems_physical_infra_helper/textual_summary.rb b/app/helpers/ems_physical_infra_helper/textual_summary.rb index dc4fc470148..9424e8f4b7d 100644 --- a/app/helpers/ems_physical_infra_helper/textual_summary.rb +++ b/app/helpers/ems_physical_infra_helper/textual_summary.rb @@ -7,7 +7,7 @@ module EmsPhysicalInfraHelper::TextualSummary def textual_group_properties TextualGroup.new( _("Properties"), - %i(hostname ipaddress type port guid) + %i(hostname type port guid) ) end @@ -37,12 +37,19 @@ def textual_group_topology # Items # - def textual_hostname - @record.hostname + def textual_hosts + label = title_for_hosts + num = @ems.number_of(:hosts) + h = {:label => label, :icon => "pficon pficon-screen", :value => num} + if num > 0 && role_allows?(:feature => "host_show_list") + h[:link] = ems_infra_path(@ems.id, :display => 'hosts') + h[:title] = _("Show all %{label}") % {:label => label} + end + h end - def textual_ipaddress - {:label => _("Discovered IP Address"), :value => @record.ipaddress} + def textual_hostname + @record.hostname end def textual_type diff --git a/app/helpers/host_helper/textual_summary.rb b/app/helpers/host_helper/textual_summary.rb index 353b7ea9438..469f17453ce 100644 --- a/app/helpers/host_helper/textual_summary.rb +++ b/app/helpers/host_helper/textual_summary.rb @@ -22,7 +22,10 @@ def textual_group_properties def textual_group_relationships TextualGroup.new( _("Relationships"), - %i(ems cluster availability_zone used_tenants storages resource_pools vms templates drift_history) + %i( + ems cluster availability_zone used_tenants storages resource_pools + vms templates drift_history physical_servers + ) ) end @@ -48,6 +51,13 @@ def textual_group_miq_custom_attributes TextualGroup.new(_("Custom Attributes"), textual_miq_custom_attributes) end + def textual_physical_servers + { + :label => _("Physical Server"), :value => @record.physical_server.try(:name), :icon => "pficon pficon-server", + :link => url_for(:controller => 'physical_server', :action => 'show', :id => @record.physical_server.try(:id)) + } + end + def textual_group_ems_custom_attributes TextualGroup.new(_("VC Custom Attributes"), textual_ems_custom_attributes) end diff --git a/app/helpers/physical_server_helper.rb b/app/helpers/physical_server_helper.rb new file mode 100644 index 00000000000..3b55f887dce --- /dev/null +++ b/app/helpers/physical_server_helper.rb @@ -0,0 +1,3 @@ +module PhysicalServerHelper + include_concern 'TextualSummary' +end diff --git a/app/helpers/physical_server_helper/textual_summary.rb b/app/helpers/physical_server_helper/textual_summary.rb new file mode 100644 index 00000000000..5eda65a9194 --- /dev/null +++ b/app/helpers/physical_server_helper/textual_summary.rb @@ -0,0 +1,44 @@ +module PhysicalServerHelper::TextualSummary + def textual_group_properties + %i(name model product_name manufacturer machine_type serial_number ems_ref) + end + + def textual_group_relationships + %i(host) + end + + def textual_group_compliance + end + + def textual_host + {:label => _("Host"), :value => @record.host.try(:name), :icon => "pficon pficon-virtual-machine", :link => url_for(:controller => 'host', :action => 'show', :id => @record.host.try(:id))} + end + + def textual_name + {:label => _("Server name"), :value => @record.name } + end + + def textual_product_name + {:label => _("Product Name"), :value => @record.product_name } + end + + def textual_manufacturer + {:label => _("Manufacturer"), :value => @record.manufacturer } + end + + def textual_machine_type + {:label => _("Machine Type"), :value => @record.machine_type } + end + + def textual_serial_number + {:label => _("Serial Number"), :value => @record.serial_number } + end + + def textual_ems_ref + {:label => _("UUID"), :value => @record.ems_ref } + end + + def textual_model + {:label => _("Model"), :value => @record.model} + end +end diff --git a/app/helpers/quadicon_helper.rb b/app/helpers/quadicon_helper.rb index 7252dd6ec39..393cdc6acac 100644 --- a/app/helpers/quadicon_helper.rb +++ b/app/helpers/quadicon_helper.rb @@ -151,6 +151,10 @@ def render_quadicon(item, options = {}) end end + def img_for_physical_vendor(item) + "svg/vendor-#{h(item.label_for_vendor.downcase)}.svg" + end + # FIXME: Even better would be to ask the object what method to use def quadicon_builder_factory(item, options) case quadicon_builder_name_from(item) @@ -163,6 +167,7 @@ def quadicon_builder_factory(item, options) when 'single_quad' then render_single_quad_quadicon(item, options) when 'storage' then render_storage_quadicon(item, options) when 'vm_or_template' then render_vm_or_template_quadicon(item, options) + when 'physical_server' then render_physical_server_quadicon(item, options) else raise "unknown quadicon kind - #{quadicon_builder_name_from(item)}" end @@ -216,6 +221,48 @@ def render_quadicon_label(item, row) end end + # Renders a quadicon for PhysicalServer + # + def render_physical_server_quadicon(item, options) + output = [] + if settings(:quadicons, :physical_server) + output << flobj_img_simple("layout/base.png") + + output << flobj_p_simple("a72", (item.host ? 1 : 0)) + output << flobj_img_simple("svg/currentstate-#{h(item.power_state.downcase)}.svg", "b72") + output << flobj_img_simple(img_for_physical_vendor(item), "c72") + output << flobj_img_simple(img_for_health_state(item), "d72") + output << flobj_img_simple('100/shield.png', "g72") unless item.get_policies.empty? + else + output << flobj_img_simple(size) + output << flobj_img_simple(width * 1.8, img_for_physical_vendor(item), "e72") + end + + if options[:typ] == :listnav + # Listnav, no href needed + output << content_tag(:div, :class => 'flobj') do + tag(:img, :src => ActionController::Base.helpers.image_path("layout/reflection.png"), :border => 0) + end + else + href = if quadicon_show_links? + if quadicon_edit_key?(:hostitems) + "/physical_server/edit/?selected_physical_server=#{item.id}" + else + url_for_record(item) + end + end + + output << content_tag(:div, :class => 'flobj') do + title = _("Name: %{name} ") % {:name => h(item.name)} + + link_to(href, :title => title) do + quadicon_reflection_img + end + end + end + safe_join(output.collect(&:html_safe)) + end + # FIXME: Even better would be to ask the object what name to use def quadicon_label_content(item, row, truncate: true) return item.address if item.kind_of? FloatingIp @@ -334,6 +381,7 @@ def quadicon_reflection_img(options = {}) end CLASSLY_NAMED_ITEMS = %w( + PhysicalServer EmsCluster ResourcePool Repository @@ -345,13 +393,16 @@ def quadicon_reflection_img(options = {}) ).freeze def quadicon_named_for_base_class?(item) - %w(ExtManagementSystem Host).include?(item.class.base_class.name) + %w(ExtManagementSystem Host PhysicalServer).include?(item.class.base_class.name) end + def quadicon_named_for_base_model?(item) + %w(VmOrTempalte PhysicalServer).include?(item.class.base_model.name) + end def quadicon_builder_name_from(item) builder_name = if CLASSLY_NAMED_ITEMS.include?(item.class.name) item.class.name.underscore - elsif item.kind_of?(VmOrTemplate) + elsif quadicon_named_for_base_model?(item) item.class.base_model.to_s.underscore elsif item.kind_of?(ManageIQ::Providers::ConfigurationManager) "single_quad" @@ -361,7 +412,6 @@ def quadicon_builder_name_from(item) # All other models that only need single large icon and use name for hover text "single_quad" end - builder_name = 'vm_or_template' if %w(miq_template vm).include?(builder_name) builder_name end @@ -505,10 +555,15 @@ def render_host_quadicon(item, options) # def render_ext_management_system_quadicon(item, options) output = [] - if settings(:quadicons, db_for_quadicon) output << flobj_img_simple("layout/base.png") - output << flobj_p_simple("a72", item.kind_of?(EmsCloud) ? item.total_vms : item.hosts.size) + item_count = case item + when EmsPhysicalInfra then item.physical_servers.size + when EmsCloud then item.total_vms + else + item.hosts.size + end + output << flobj_p_simple("a72", item_count) output << flobj_p_simple("b72", item.total_miq_templates) if item.kind_of?(EmsCloud) output << flobj_img_simple("svg/vendor-#{h(item.image_name)}.svg", "c72") output << flobj_img_simple(img_for_auth_status(item), "d72") @@ -641,6 +696,15 @@ def render_single_quad_quadicon(item, options) output.collect(&:html_safe).join('').html_safe end + def img_for_health_state(item) + case item.health_state + when "Valid" then "100/healthstate-normal.png" + when "Critical" then "svg/healthstate-critical.svg" + when "None" then "svg/healthstate-unknown.svg" + when "Warning" then "100/warning.png" + end + end + # Renders a storage quadicon # def render_storage_quadicon(item, options) diff --git a/app/helpers/ui_constants.rb b/app/helpers/ui_constants.rb index 25ea145b791..1e613c1291d 100644 --- a/app/helpers/ui_constants.rb +++ b/app/helpers/ui_constants.rb @@ -155,13 +155,14 @@ module UiConstants # Default UI settings DEFAULT_SETTINGS = { :quadicons => { # Show quad icons, by resource type - :service => true, - :ems => true, - :ems_cloud => true, - :host => true, - :miq_template => true, - :storage => true, - :vm => true + :service => true, + :ems => true, + :ems_cloud => true, + :host => true, + :miq_template => true, + :storage => true, + :vm => true, + :physical_server => true }, :views => { # List view setting, by resource type :authkeypaircloud => "list", @@ -207,6 +208,7 @@ module UiConstants :manageiq_providers_inframanager_vm => "grid", :manageiq_providers_inframanager_template => "list", :manageiq_providers_middlewaremanager => "grid", + :manageiq_providers_physicalinframanager => "grid", :manageiq_providers_storagemanager => "list", :middlewaredatasource => "list", :middlewaredeployment => "list", @@ -229,6 +231,7 @@ module UiConstants :storagemanager => "list", :miqtask => "list", :ms => "grid", + :physicalserver => "grid", :policy => "list", :policyset => "grid", :resourcepool => "grid", diff --git a/app/views/layouts/listnav/_physical_server.html.haml b/app/views/layouts/listnav/_physical_server.html.haml new file mode 100644 index 00000000000..d34f90f66f6 --- /dev/null +++ b/app/views/layouts/listnav/_physical_server.html.haml @@ -0,0 +1,24 @@ +- if @record.try(:name) + #accordion.panel-group + = miq_accordion_panel(truncate(@record.name, :length => truncate_length), true, "icon") do + = render_quadicon(@record, :mode => :icon, :size => 72, :typ => :listnav) + + = miq_accordion_panel(_("Properties"), false, "ems_prop") do + %ul.nav.nav-pills.nav-stacked + %li + = link_to(_('Summary'), {:action => 'show', :id => @record, :display => 'main'}, {:title => _("Show Summary")}) + + = miq_accordion_panel(_("Relationships"), false, "ems_rel") do + %ul.nav.nav-pills.nav-stacked + - if @record.ext_management_system + %li + = link_to("#{ui_lookup(:table => "ext_management_systems")}: #{@record.ext_management_system.name}", + ems_physical_infra_path(@record.ext_management_system.id), + :title => _("Show this parent Provider")) + - if @record.host + %li + = link_to("#{ui_lookup(:table => "host")}: #{@record.host.name}", + "/host/show/#{@record.host.id}", + :title => _("Show Host")) + + diff --git a/app/views/physical_server/_config.html.haml b/app/views/physical_server/_config.html.haml new file mode 100644 index 00000000000..fe569d3659d --- /dev/null +++ b/app/views/physical_server/_config.html.haml @@ -0,0 +1,54 @@ += render :partial => "layouts/flash_msg" +- case @display +- when "devices" + - unless @devices.empty? + .form-horizontal.static + .form-group + - @devices.each do |item| + %label.col-md-2.control-label + = h(item[:device]) + .col-md-10 + %p.form-control-static + %img{:src => image_path("100/hardware-#{item[:icon].downcase}.png")} + = h(item[:description]) +- when "os_info" + - if @osinfo + .form-horizontal.static + .form-group + - @osinfo.each do |item| + %label.col-md-2.control-label + = h(item[:osinfo]) + .col-md-10 + %p.form-control-static + = h(item[:description]) + .form-group + %label.col-md-2.control-label + = _('Hostname') + .col-md-10 + %p.form-control-static + = h(@host.hostname) + .form-group + %label.col-md-2.control-label + = _('IP Address') + .col-md-10 + %p.form-control-static + = h(@host.ipaddress) + +- when "hv_info" + - if @vmminfo + .form-horizontal.static + .form-group + - @vmminfo.each do |item| + %label.col-md-2.control-label + = h(item[:vmminfo]) + .col-md-10 + %p.form-control-static + = h(item[:description]) +- when "network" + = render :partial => "network_tree" + +- when "storage_adapters" + %table{:style => "height: 100px;"} + %tr + %td{:width => "55%", :valign => "top"} + = render :partial => "network_tree" diff --git a/app/views/physical_server/_form.html.haml b/app/views/physical_server/_form.html.haml new file mode 100644 index 00000000000..ff1b4e7c479 --- /dev/null +++ b/app/views/physical_server/_form.html.haml @@ -0,0 +1,108 @@ +- @angular_form = true + +.form-horizontal{:id => "start_form_div", :style => "display:none"} + %form#form_div{"name" => "angularForm", + "ng-controller" => "hostFormController", + "ng-show" => "afterGet", + "form-fields-url" => "/#{controller_name}/host_form_fields/", + "create-url" => "/#{controller_name}/create/", + "update-url" => "/#{controller_name}/update/", + "novalidate" => true, + "start-form-div" => "start_form_div"} + = render :partial => "layouts/flash_msg" + - if session[:host_items].nil? + %div + %div + .form-group{"ng-class" => "{'has-error': angularForm.name.$invalid}"} + %label.col-md-2.control-label{"for" => "name"} + = _("Name") + .col-md-8 + %input.form-control{"type" => "text", + "id" => "name", + "name" => "name", + "ng-model" => "hostModel.name", + "maxlength" => MAX_NAME_LEN.to_s, + "miqrequired" => "", + "checkchange" => "", + "auto-focus" => ""} + %span.help-block{"ng-show" => "angularForm.name.$error.miqrequired"} + = _("Required") + .form-group{"ng-class" => "{'has-error': angularForm.hostname.$invalid}"} + %label.col-md-2.control-label{"for" => "hostname"} + = _("Hostname (or IPv4 or IPv6 address)") + .col-md-4 + %input.form-control{"type" => "text", + "id" => "hostname", + "name" => "hostname", + "ng-model" => "hostModel.hostname", + "maxlength" => MAX_HOSTNAME_LEN.to_s, + "miqrequired" => "", + "checkchange" => ""} + %span.help-block{"ng-show" => "angularForm.hostname.$error.miqrequired"} + = _("Required") + .form-group{"ng-class" => "{'has-error': angularForm.user_assigned_os.$invalid}", "ng-hide" => "hostModel.operating_system"} + %label.col-md-2.control-label + = _("Host platform") + .col-md-8 + = select_tag('user_assigned_os', + options_for_select([["<#{_('Choose')}>", nil]] + Host.host_create_os_types.to_a, :disabled => ["<#{_('Choose')}>", nil]), + "ng-model" => "hostModel.user_assigned_os", + "checkchange" => "", + "ng-required" => "!hostModel.operating_system", + "selectpicker-for-select-tag" => "") + %span.help-block{"ng-show" => "angularForm.user_assigned_os.$error.required"} + = _("Required") + .form-group + %label.col-md-2.control-label + = _("Custom Identifier") + .col-md-8 + %input#custom_1.form-control{"type" => "text", + "name" => "custom_1", + "ng-model" => "hostModel.custom_1", + "maxlength" => 50, + "checkchange" => ""} + .form-group{"ng-class" => "{'has-error': angularForm.ipmi_address.$error.requiredDependsOn}"} + %label.col-md-2.control-label{"for" => "ipmi_address"} + = _("IPMI IP Address") + .col-md-8 + %input.form-control#ipmi_address{"type" => "text", + "id" => "ipmi_address", + "name" => "ipmi_address", + "ng-model" => "hostModel.ipmi_address", + "required-depends-on" => "hostModel.ipmi_userid", + "required-if-exists" => "ipmi_userid", + "maxlength" => 15, + "checkchange" => ""} + %span.help-block{"ng-show" => "angularForm.ipmi_address.$error.requiredDependsOn"} + = _("Required") + .form-group + %label.col-md-2.control-label + = _("MAC Address") + .col-md-8 + %input#mac_address.form-control{"type" => "text", + "name" => "mac_address", + "ng-model" => "hostModel.mac_address", + "maxlength" => MAX_NAME_LEN.to_s, + "checkchange" => ""} + %hr + = render(:partial => "/layouts/angular/multi_auth_credentials", + :locals => {:record => @host, :ng_model => "hostModel"}) + = render :partial => "layouts/angular/x_edit_buttons_angular" + + - unless session[:host_items].nil? + %h3 + = n_("Host", "Hosts", session[:host_items].length) + = _('Selected') + = _('Click on a Host to fetch its settings') + %table.admittable{:height => '75'} + %tbody + %tr + %td + - if session[:host_items] + - @embedded = true + - @gtl_type = settings(:views, :host) + = render :partial => 'layouts/gtl' + +:javascript + ManageIQ.angular.app.value('hostFormId', '#{(@host.id || (session[:host_items] && session[:host_items].join(","))) || "new"}'); + miq_bootstrap('#form_div'); diff --git a/app/views/physical_server/_main.html.haml b/app/views/physical_server/_main.html.haml new file mode 100644 index 00000000000..e98bdb4732c --- /dev/null +++ b/app/views/physical_server/_main.html.haml @@ -0,0 +1,7 @@ += render :partial => "layouts/flash_msg" +.row + .col-md-12.col-lg-6 + = render :partial => "shared/summary/textual", :locals => {:title => _("Properties"), :items => textual_group_properties} + = render :partial => "shared/summary/textual", :locals => {:title => _("Relationships"), :items => textual_group_relationships} + .col-md-12.col-lg-6 + TODO: other groups diff --git a/app/views/physical_server/_network_tree.html.haml b/app/views/physical_server/_network_tree.html.haml new file mode 100644 index 00000000000..1df624feed3 --- /dev/null +++ b/app/views/physical_server/_network_tree.html.haml @@ -0,0 +1,9 @@ +-# Network or Storage Adpater Tree +- if x_active_tree == :sa_tree + %div + = render(:partial => 'shared/tree', :locals => {:tree => @sa_tree, :name => @sa_tree.name.to_s}) +- else + %div{:id => "#{session[:tree_name]}box", :style => "width: 100%"} + = render(:partial => 'shared/tree', :locals => {:tree => @network_tree, :name => @network_tree.name.to_s}) + + diff --git a/app/views/physical_server/discover.html.haml b/app/views/physical_server/discover.html.haml new file mode 100644 index 00000000000..946660d7931 --- /dev/null +++ b/app/views/physical_server/discover.html.haml @@ -0,0 +1 @@ += render :partial => "layouts/discover" diff --git a/app/views/physical_server/edit.html.haml b/app/views/physical_server/edit.html.haml new file mode 100644 index 00000000000..c66fabf2cd6 --- /dev/null +++ b/app/views/physical_server/edit.html.haml @@ -0,0 +1 @@ += render :partial => 'form' diff --git a/app/views/physical_server/new.html.haml b/app/views/physical_server/new.html.haml new file mode 100644 index 00000000000..c66fabf2cd6 --- /dev/null +++ b/app/views/physical_server/new.html.haml @@ -0,0 +1 @@ += render :partial => 'form' diff --git a/app/views/physical_server/show.html.haml b/app/views/physical_server/show.html.haml new file mode 100644 index 00000000000..5a4dd6016e2 --- /dev/null +++ b/app/views/physical_server/show.html.haml @@ -0,0 +1,34 @@ +#main_div + - arr = %w(physical_server physical_servers vms cloud_tenants storages miq_proxies miq_templates) + - arr.concat(%w(resource_pools ontap_logical_disks ontap_storage_systems ontap_storage_volumes ontap_file_shares)) + - if arr.include?(@display) && @showtype != "compare" + = render(:partial => "layouts/gtl", :locals => {:action_url => "show/#{@ph_server.id}"}) + - else + - case @showtype + - when "details" + = render(:partial => "layouts/gtl", :locals => {:action_url => @lastaction}) + - when "compare", "drift" + -# TODO: (odravison) The raise was put before render method + -# I changed to inverse + = render(:partial => "layouts/compare") + = raise 'compare or drift partial called through "show"' + - when "drift_history", "item" + = render(:partial => "layouts/#{@showtype}") + - when "performance" + = render(:partial => "layouts/performance") + :javascript + ManageIQ.afterOnload = "miqAsyncAjax('#{url_for(:action => @ajax_action, :id => @record)}');" + - when "performance_summary" + = render(:partial => "layouts/performance_summary") + - when "timeline" + = render(:partial => "layouts/tl_show") + :javascript + ManageIQ.afterOnload = "miqAsyncAjax('#{url_for(:action => @ajax_action, :id => @record)}');" + - when "download_pdf" + = render(:partial => "layouts/show_pdf") + - when "dialog_provision" + = render(:partial => "shared/dialogs/dialog_provision") + - when "compliance_history" + = render(:partial => "shared/views/#{@showtype}") + - else + = render(:partial => @showtype) diff --git a/app/views/physical_server/show_list.html.haml b/app/views/physical_server/show_list.html.haml new file mode 100644 index 00000000000..039604839f2 --- /dev/null +++ b/app/views/physical_server/show_list.html.haml @@ -0,0 +1,2 @@ +#main_div + = render :partial => 'layouts/gtl' diff --git a/app/views/physical_server/show_policy_timeline.html.haml b/app/views/physical_server/show_policy_timeline.html.haml new file mode 100644 index 00000000000..ddece093b5d --- /dev/null +++ b/app/views/physical_server/show_policy_timeline.html.haml @@ -0,0 +1,2 @@ +#main_div + = render :partial => "layouts/tl_show" diff --git a/app/views/shared/views/ems_common/_show.html.haml b/app/views/shared/views/ems_common/_show.html.haml index 0bb8d604849..9ea96ca5b45 100644 --- a/app/views/shared/views/ems_common/_show.html.haml +++ b/app/views/shared/views/ems_common/_show.html.haml @@ -5,7 +5,8 @@ - arr.concat(%w(security_groups floating_ips cloud_subnets network_routers network_ports cloud_networks)) - arr.concat(%w(load_balancers container_templates)) - arr.concat(%w(cloud_tenants ems_clusters flavors resource_group hosts instances images miq_templates cloud_volumes)) - - arr.concat(%w(storage_managers cloud_volume_snapshots orchestration_stacks vms storages miq_proxies persistent_volumes cloud_object_store_containers)) + - arr.concat(%w(storage_managers cloud_volume_snapshots orchestration_stacks vms storages miq_proxies)) + - arr.concat(%w(physical_servers persistent_volumes cloud_object_store_containers)) - if arr.include?(@display) && @showtype != "compare" = render :partial => "layouts/gtl", :locals => {:action_url => "show/#{@ems.id}"} - elsif @showtype == "details" diff --git a/config/routes.rb b/config/routes.rb index 448a6feebcb..39e65fc22ec 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1269,6 +1269,24 @@ save_post }, + :physical_server => { + :get => %w( + download_data + perf_top_chart + protect + show_list + show + ) + compare_get, + + :post => %w( + button + show_list + create + update + + ) + }, + :ems_physical_infra_dashboard => { :get => %w( show