ManageIQ/manageiq-providers-autosde

View on GitHub
app/models/manageiq/providers/autosde/storage_manager.rb

Summary

Maintainability
A
0 mins
Test Coverage
D
66%
class ManageIQ::Providers::Autosde::StorageManager < ManageIQ::Providers::StorageManager
  supports :authentication_status
  supports :create
  supports :storage_services
  supports :storage_service_create
  supports :update
  supports :volume_resizing
  supports :cloud_volume_snapshots
  supports :cloud_volume_create
  supports :cloud_volume
  supports :catalog
  supports :storage_service_resource_attachments

  supports :add_storage
  supports :add_host_initiator
  supports :add_volume_mapping

  include ManageIQ::Providers::StorageManager::BlockMixin

  # Asset details
  has_many :physical_server_details,  :through => :physical_servers,  :source => :asset_detail
  has_many :physical_storage_details, :through => :physical_storages, :source => :asset_detail
  # TODO: (erezt):
  # has_many :services_details, :through => :services, :source => :asset_detail
  # has_many :resources_details, :through => :resources, :source => :asset_detail

  # Computer systems
  has_many :physical_server_computer_systems,  :through => :physical_servers,  :source => :computer_system
  has_many :physical_storage_computer_systems, :through => :physical_storages, :source => :canister_computer_systems

  # Network
  has_many :physical_server_networks,  :through => :physical_server_management_devices,  :source => :network
  has_many :physical_storage_networks, :through => :physical_storage_management_devices, :source => :network

  # Physical network ports
  has_many :physical_server_network_ports,  :through => :physical_server_network_devices,     :source => :physical_network_ports
  has_many :physical_storage_network_ports, :through => :physical_storage_management_devices, :source => :physical_network_ports

  # Physical disks
  has_many :physical_disks, :through => :physical_storages

  has_many :host_volume_mappings, :foreign_key => :ems_id, :inverse_of => :ext_management_system,
           :class_name => "ManageIQ::Providers::Autosde::StorageManager::HostVolumeMapping"
  has_many :cluster_volume_mappings, :foreign_key => :ems_id, :inverse_of => :ext_management_system,
           :class_name => "ManageIQ::Providers::Autosde::StorageManager::ClusterVolumeMapping"

  virtual_total :total_physical_servers,  :physical_servers
  virtual_total :total_physical_storages, :physical_storages

  virtual_column :total_hosts, :type => :integer
  virtual_column :total_vms,   :type => :integer

  virtual_column :total_valid, :type => :integer
  virtual_column :total_warning, :type => :integer
  virtual_column :total_critical, :type => :integer
  virtual_column :health_state_info, :type => :json

  virtual_column :total_resources, :type => :integer
  virtual_column :resources_info, :type => :json

  class << model_name
    define_method(:route_key) { "ems_block_storages" }
    define_method(:singular_route_key) { "ems_block_storage" }
  end

  def queue_name_for_ems_refresh
    queue_name
  end

  def self.ems_type
    @ems_type ||= "storage_manager".freeze
  end

  def self.description
    @description ||= "StorageManager".freeze
  end

  def count_health_state(state)
    count = 0
    count += physical_servers.where(:health_state => state).count
    count += physical_storages.where(:health_state => state).count
  end

  def assign_health_states
    {
      :total_valid    => count_health_state("Valid"),
      :total_warning  => count_health_state("Warning"),
      :total_critical => count_health_state("Critical"),
    }
  end

  alias health_state_info assign_health_states

  def count_resources(component = nil)
    count = 0

    if component
      count = component.count
    else
      count += physical_servers.count
      count += physical_storages.count
    end
  end

  def assign_resources_info
    {
      :total_resources => count_resources,
    }
  end

  alias resources_info assign_resources_info

  def count_physical_servers_with_host
    physical_servers.inject(0) { |t, physical_server| physical_server.host.nil? ? t : t + 1 }
  end

  alias total_hosts count_physical_servers_with_host

  def count_vms
    physical_servers.inject(0) { |t, physical_server| physical_server.host.nil? ? t : t + physical_server.host.vms.size }
  end

  alias total_vms count_vms

  def self.display_name(number = 1)
    n_('Storage Manager', 'Storage Managers', number)
  end

  def textual_group_list
    [
      %i[properties status],
      %i[storage_relationships topology]
    ]
  end

  def autosde_client
    if @autosde_client.nil?
      @autosde_client = self.class.raw_connect(authentication_userid,
                                               authentication_password,
                                               address,
                                               port)
    end
    @autosde_client
  end

  def self.verify_credentials(options = {})
    raw_connect(options["authentications"]["default"]["userid"],
                ManageIQ::Password.try_decrypt(options["authentications"]["default"]["password"]),
                options["endpoints"]["default"]["hostname"],
                options["endpoints"]["default"]["port"]).login
  end

  # is this just for verifying credentials for when you create a new instance?
  # todo (per gregoryb): need to enable users to provide client_id and secret_id
  def verify_credentials(_auth_type = nil, _options = {})
    begin
      connect
    rescue => err
      raise MiqException::MiqInvalidCredentialsError, err.message
    end

    true
  end

  # is this just for verifying credentials for when you create a new instance?
  def connect(options = {})
    raise MiqException::MiqHostError, "No credentials defined" if missing_credentials?(options[:auth_type])

    auth_token = authentication_token(options[:auth_type])
    username   = options[:user] || authentication_userid(options[:auth_type])
    password   = options[:pass] || authentication_password(options[:auth_type])
    host       = options[:host] || address
    port       = options[:port] || self.port
    self.class.raw_connect(username, password, host, port).login
  end

  def self.validate_authentication_args(params)
    # return args to be used in raw_connect
    [params[:default_userid], ManageIQ::Password.encrypt(params[:default_password])]
  end

  # is this just for verifying credentials for when you create a new instance?
  # @return AutosdeClient
  def self.raw_connect(username, password, host, port)
    ManageIQ::Providers::Autosde::StorageManager::AutosdeClient.new(:username => username, :password => password, :host => host, :port => port)
  end

  def self.hostname_required?
    # TODO: ExtManagementSystem is validating this
    false
  end

  def self.ems_type
    @ems_type ||= "autosde".freeze
  end

  def self.description
    @description ||= "Autosde".freeze
  end

  def self.params_for_create
    {
      :fields => [
        {
          :component => 'sub-form',
          :id        => 'endpoints-subform',
          :name      => 'endpoints-subform',
          :title     => _('Endpoints'),
          :fields    => [
            {
              :component              => 'validate-provider-credentials',
              :id                     => 'authentications.default.valid',
              :name                   => 'authentications.default.valid',
              :skipSubmit             => true,
              :validationDependencies => %w[type zone_id endpoints.default.hostname authentications.default.userid authentications.default.password],
              :fields                 => [
                {
                  :component  => "select",
                  :id         => "endpoints.default.security_protocol",
                  :name       => "endpoints.default.security_protocol",
                  :label      => _("Security Protocol"),
                  :isRequired => true,
                  :validate   => [{:type => "required"}],
                  :includeEmpty => true,
                  :options    => [
                    {
                      :label => _("SSL without validation"),
                      :value => "ssl-no-validation"
                    }
                    # todo[per gregoryb]: need to provide ssl and non-ssl
                    # {
                    #     :label => _("SSL"),
                    #     :value => "ssl-with-validation"
                    # },
                    # {
                    #     :label => _("Non-SSL"),
                    #     :value => "non-ssl"
                    # }
                  ]
                },
                {
                  :component  => "text-field",
                  :id         => "endpoints.default.hostname",
                  :name       => "endpoints.default.hostname",
                  :label      => _("Hostname (or IPv4 or IPv6 address)"),
                  :isRequired => true,
                  :validate   => [{:type => "required"}],
                },
                {
                  :component    => "text-field",
                  :id           => "endpoints.default.port",
                  :name         => "endpoints.default.port",
                  :label        => _("API Port"),
                  :type         => "number",
                  :initialValue => 443,
                  :isRequired   => true,
                  :validate     => [{:type => "required"}],
                },
                {
                  :component  => "text-field",
                  :id         => "authentications.default.userid",
                  :name       => "authentications.default.userid",
                  :label      => _("Username"),
                  :isRequired => true,
                  :validate   => [{:type => "required"}],
                },
                {
                  :component  => "password-field",
                  :id         => "authentications.default.password",
                  :name       => "authentications.default.password",
                  :label      => _("Password"),
                  :type       => "password",
                  :isRequired => true,
                  :validate   => [{:type => "required"}],
                },
              ]
            }
          ],
        },
      ]
    }
  end

  def self.catalog_types
    {"autosde" => N_("Autosde")}
  end

  def self.post_refresh_ems(ems_id, _)
    events = EmsEvent.where("ems_id = ? AND (physical_storage_id IS NULL OR physical_storage_name IS NULL)", ems_id)

    events.each do |e|
      physical_storage_uuid = e.full_data[:storage_system]
      physical_storage = PhysicalStorage.find_by(:ems_id => ems_id, :ems_ref => physical_storage_uuid)

      e.physical_storage_name = physical_storage.name
      e.physical_storage_id = physical_storage.id
      e.save
    end
  end
end