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