ManageIQ/manageiq-providers-ibm_cloud

View on GitHub
app/models/manageiq/providers/ibm_cloud/power_virtual_servers/storage_manager/cloud_volume.rb

Summary

Maintainability
A
1 hr
Test Coverage
F
33%
class ManageIQ::Providers::IbmCloud::PowerVirtualServers::StorageManager::CloudVolume < ::CloudVolume
  supports :create
  supports :clone
  supports :delete do
    return _("the volume is not connected to an active Provider") unless ext_management_system
    return _("cannot delete volume that is in use.") if status == "in-use"
  end
  supports_not :snapshot_create
  supports_not :update
  supports :attach do
    return _("the volume is not connected to an active Provider") unless ext_management_system
    return _("cannot attach non-shareable volume that is in use.") if status == "in-use" && !multi_attachment
  end
  supports :detach do
    return _("the volume is not connected to an active Provider") unless ext_management_system
    return _("the volume status is '%{status}' but should be 'in-use'") % {:status => status} unless status == "in-use"
  end

  def available_vms
    availability_zone.vms.select { |vm| vm.format == volume_type }
  end

  def cloud_instance_id
    ext_management_system.parent_manager.uid_ems
  end

  def self.params_for_create(ems)
    {
      :fields => [
        {
          :component  => 'text-field',
          :name       => 'size',
          :id         => 'size',
          :label      => _('Size (in bytes)'),
          :type       => 'number',
          :step       => 1.gigabytes,
          :isRequired => true,
          :validate   => [{:type => 'required'}, {:type => 'min-number-value', :value => 0, :message => _('Size must be greater than or equal to 0')}],
        },
        {
          :component => 'switch',
          :name      => 'multi_attachment',
          :id        => 'multi_attachment',
          :label     => _('Shareable'),
          :onText    => _('Yes'),
          :offText   => _('No'),
        },
        {
          :component    => 'select',
          :name         => 'affinity_policy',
          :id           => 'affinity_policy',
          :label        => _('Affinity Policy'),
          :initialValue => 'Off',
          :options      => [
            {
              :label => _('Off'),
              :value => 'Off',
            },
            {
              :label => _('Affinity'),
              :value => 'affinity',
            },
            {
              :label => _('Anti-affinity'),
              :value => 'anti-affinity',
            },
          ],
        },
        {
          :component    => 'select',
          :name         => 'volume_type',
          :id           => 'volume_type',
          :label        => _('Cloud Volume Type'),
          :validate     => [{:type => 'required'}],
          :condition    => {
            :when    => 'affinity_policy',
            :pattern => '^Off$',
          },
          :includeEmpty => true,
          :options      => ems.cloud_volume_types.map do |cvt|
            {
              :label => cvt.description,
              :value => cvt.name,
            }
          end,
        },
        {
          :component    => 'select',
          :name         => 'affinity_type',
          :id           => 'affinity_type',
          :label        => _('Affinity Type'),
          :includeEmpty => true,
          :condition    => {
            :not => [
              {
                :when    => 'affinity_policy',
                :pattern => '^Off$',
              },
            ]
          },
          :options      => [
            {
              :label => _('Volume'),
              :value => 'volume',
            },
            {
              :label => _('PVM Instance'),
              :value => 'pvm_instance',
            },
          ],
        },
        {
          :component    => 'select',
          :isSearchable => true,
          :name         => 'affinity_volume',
          :id           => 'affinity_volume',
          :label        => _('Affinity Volume'),
          :validate     => [{:type => 'required'}],
          :condition    => {
            :and => [
              {
                :when    => 'affinity_policy',
                :pattern => '^affinity$',
              },
              {
                :when    => 'affinity_type',
                :pattern => 'volume$',
              },
            ]
          },
          :includeEmpty => true,
          :options      => ems.cloud_volumes.map do |cv|
            {
              :label => cv.name,
              :value => cv.ems_ref,
            }
          end,
        },
        {
          :component    => 'select',
          :isMulti      => true,
          :isClearable  => true,
          :isSearchable => true,
          :name         => 'anti_affinity_volumes',
          :id           => 'anti_affinity_volumes',
          :label        => _('Anti-Affinity Volume(s)'),
          :validate     => [{:type => 'required'}],
          :condition    => {
            :and => [
              {
                :when    => 'affinity_policy',
                :pattern => '^anti-affinity$',
              },
              {
                :when    => 'affinity_type',
                :pattern => 'volume$',
              },
            ]
          },
          :includeEmpty => true,
          :options      => ems.cloud_volumes.map do |cv|
            {
              :label => cv.name,
              :value => cv.ems_ref,
            }
          end,
        },
        {
          :component    => 'select',
          :isSearchable => true,
          :name         => 'affinity_pvm_instance',
          :id           => 'affinity_pvm_instance',
          :label        => _('Affinity PVM Instance'),
          :validate     => [{:type => 'required'}],
          :condition    => {
            :and => [
              {
                :when    => 'affinity_policy',
                :pattern => '^affinity$',
              },
              {
                :when    => 'affinity_type',
                :pattern => 'pvm_instance$',
              },
            ]
          },
          :includeEmpty => true,
          :options      => ems.parent_manager.vms.map do |vm|
            {
              :label => vm.name,
              :value => vm.ems_ref,
            }
          end,
        },
        {
          :component    => 'select',
          :isMulti      => true,
          :isClearable  => true,
          :isSearchable => true,
          :name         => 'anti_affinity_pvm_instances',
          :id           => 'anti_affinity_pvm_instances',
          :label        => _('Anti-Affinity PVM Instance(s)'),
          :validate     => [{:type => 'required'}],
          :condition    => {
            :and => [
              {
                :when    => 'affinity_policy',
                :pattern => '^anti-affinity$',
              },
              {
                :when    => 'affinity_type',
                :pattern => 'pvm_instance$',
              },
            ]
          },
          :includeEmpty => true,
          :options      => ems.parent_manager.vms.map do |vm|
            {
              :label => vm.name,
              :value => vm.ems_ref,
            }
          end,
        },
      ],
    }
  end

  def params_for_clone
    {
      :fields => [
        {
          :component  => 'text-field',
          :name       => 'name',
          :id         => 'name',
          :label      => _('Volume Base Name'),
          :isRequired => true,
          :helperText => _("Base name of the new cloned volume. The cloned Volume name will be prefixed with 'clone-' and suffixed with '-#####' (where ##### is a 5 digit random number)"),
        },
      ]
    }
  end

  def params_for_attach
    {
      :fields => []
    }
  end

  def self.raw_create_volume(ext_management_system, options)
    volume = nil
    volume_params = nil
    affinity_volume = nil
    anti_affinity_volumes = nil
    affinity_pvm_instance = nil
    anti_affinity_pvm_instances = nil

    affinity_policy = options['affinity_policy'] == 'Off' ? nil : options['affinity_policy']

    case affinity_policy
    when 'affinity'
      case options['affinity_type']
      when 'volume'
        affinity_volume = options['affinity_volume']['value']
      when 'pvm_instance'
        affinity_pvm_instance = options['affinity_pvm_instance']['value']
      end
    when 'anti-affinity'
      case options['affinity_type']
      when 'volume'
        anti_affinity_volumes = options['anti_affinity_volumes'].map { |vol| vol['value'] }
      when 'pvm_instance'
        anti_affinity_pvm_instances = options['anti_affinity_pvm_instances'].map { |vol| vol['value'] }
      end
    end

    ext_management_system.with_provider_connection(:service => 'PCloudVolumesApi') do |api|
      volume_params = IbmCloudPower::CreateDataVolume.new(
        'name'                        => options['name'],
        'size'                        => options['size'].to_i / 1.0.gigabyte,
        'disk_type'                   => options['volume_type'],
        'shareable'                   => options['multi_attachment'],
        'affinity_policy'             => affinity_policy,
        'affinity_volume'             => affinity_volume,
        'anti_affinity_volumes'       => anti_affinity_volumes,
        'affinity_pvm_instance'       => affinity_pvm_instance,
        'anti_affinity_pvm_instances' => anti_affinity_pvm_instances
      )

      volume = api.pcloud_cloudinstances_volumes_post(
        ext_management_system.parent_manager.uid_ems,
        volume_params
      )
    end
    {:ems_ref => volume.volume_id, :status => volume.state, :name => volume.name}
  rescue => e
    _log.error("volume=[#{volume_params}], error: #{e}")
    raise MiqException::MiqVolumeCreateError, e.to_s, e.backtrace
  end

  def raw_delete_volume
    ext_management_system.with_provider_connection(:service => 'PCloudVolumesApi') do |api|
      api.pcloud_cloudinstances_volumes_delete(cloud_instance_id, ems_ref)
    end
  rescue => e
    _log.error("volume=[#{name}], error: #{e}")
    raise MiqException::MiqVolumeDeleteError, e.to_s, e.backtrace
  end

  def raw_attach_volume(vm_ems_ref, _device = nil)
    with_provider_connection(:service => 'PCloudVolumesApi') do |api|
      api.pcloud_pvminstances_volumes_post(cloud_instance_id, vm_ems_ref, ems_ref)
    end
  rescue => e
    _log.error("volume=[#{name}], error: #{e}")
    raise MiqException::MiqVolumeAttachError, _("Unable to attach volume: %{error_message}") % {:error_message => e.message}
  end

  def raw_detach_volume(vm_ems_ref)
    with_provider_connection(:service => 'PCloudVolumesApi') do |api|
      api.pcloud_pvminstances_volumes_delete(cloud_instance_id, vm_ems_ref, ems_ref)
    end
  rescue => e
    _log.error("volume=[#{name}], error: #{e}")
    raise MiqException::MiqVolumeDetachError, _("Unable to detach volume: %{error_message}") % {:error_message => e.message}
  end

  def raw_clone_volume(options)
    options[:volume_ids] = [ems_ref]
    with_provider_connection(:service => 'PCloudVolumesApi') do |api|
      clone_volume_params = IbmCloudPower::VolumesCloneAsyncRequest.new(
        :name        => options['name'],
        :volume_ids => options[:volume_ids]
      )
      api.pcloud_v2_volumes_clone_post(
        cloud_instance_id,
        clone_volume_params
      )
    end
  rescue => e
    _log.error("volume=[#{name}], error: #{e}")
    raise MiqException::MiqVolumeCloneError, e.to_s, e.backtrace
  end
end