Source code for cfme.cloud.instance.openstack

# -*- coding: utf-8 -*-
import attr
from navmazing import NavigateToSibling
from widgetastic.widget import View, NoSuchElementException
from widgetastic_patternfly import Button, BootstrapSelect
from widgetastic_manageiq import CheckboxSelect, Select, Input

from cfme.exceptions import OptionNotAvailable, DestinationNotFound
from cfme.common.vm_views import RightSizeView
from cfme.utils.appliance.implementations.ui import CFMENavigateStep, navigator, navigate_to
from . import Instance, InstanceCollection, CloudInstanceView

@attr.s
[docs]class OpenStackInstance(Instance): # CFME & provider power control options START = "Start" # START also covers RESUME and UNPAUSE (same as in CFME 5.4+ web UI) POWER_ON = START # For compatibility with the infra objects. SUSPEND = "Suspend" DELETE = "Delete" TERMINATE = 'Delete' # CFME-only power control options SOFT_REBOOT = "Soft Reboot" HARD_REBOOT = "Hard Reboot" # Provider-only power control options STOP = "Stop" PAUSE = "Pause" RESTART = "Restart" SHELVE = "Shelve" SHELVE_OFFLOAD = "Shelve Offload" # CFME power states STATE_ON = "on" STATE_OFF = "off" STATE_ERROR = "non-operational" STATE_PAUSED = "paused" STATE_SUSPENDED = "suspended" STATE_REBOOTING = "reboot_in_progress" STATE_SHELVED = "shelved" STATE_SHELVED_OFFLOAD = "shelved_offloaded" STATE_UNKNOWN = "unknown" STATE_ARCHIVED = "archived" STATE_TERMINATED = "terminated" @property def ui_powerstates_available(self): return { 'on': [self.SUSPEND, self.SOFT_REBOOT, self.HARD_REBOOT, self.TERMINATE], 'off': [self.START, self.TERMINATE]} @property def ui_powerstates_unavailable(self): return { 'on': [self.START], 'off': [self.SUSPEND, self.SOFT_REBOOT, self.HARD_REBOOT]}
[docs] def attach_volume(self, name, mountpoint=None): view = navigate_to(self, 'AttachVolume') view.form.fill({ 'volume': name, 'mountpoint': mountpoint }) view.form.submit_button.click()
[docs] def detach_volume(self, name): view = navigate_to(self, 'DetachVolume') view.form.volume.fill(name) view.form.submit_button.click()
@property def volume_count(self): """ number of attached volumes to instance. Returns: :py:class:`int` volume count. """ view = navigate_to(self, 'Details') return int(view.entities.summary('Relationships').get_text_of('Cloud Volumes'))
@attr.s
[docs]class OpenstackInstanceCollection(InstanceCollection): ENTITY = OpenStackInstance
[docs]class AddFloatingIPView(CloudInstanceView): @View.nested class form(View): # noqa ip = Select(name='floating_ip') submit_button = Button('Submit') cancel_button = Button('Cancel') @property def is_displayed(self): # Only the instance name is displayed, cannot confirm provider return False
[docs]class RemoveFloatingIPView(CloudInstanceView): @View.nested class form(View): # noqa ip = Select('floating_ip') submit_button = Button('Submit') cancel_button = Button('Cancel') @property def is_displayed(self): # Only the instance name is displayed, cannot confirm provider return False
[docs]class AttachVolumeView(CloudInstanceView): @View.nested class form(View): # noqa volume = BootstrapSelect('volume_id') mountpoint = Input(name='device_path') submit_button = Button('Submit') cancel_button = Button('Cancel') @property def is_displayed(self): # Only the instance name is displayed, cannot confirm provider return False
[docs]class DetachVolumeView(CloudInstanceView): @View.nested class form(View): # noqa volume = BootstrapSelect('volume_id') submit_button = Button('Submit') cancel_button = Button('Cancel') @property def is_displayed(self): # Only the instance name is displayed, cannot confirm provider return False
[docs]class EvacuateView(CloudInstanceView): @View.nested class form(View): # noqa auto_select = CheckboxSelect('auto_select_host') shared_storage = CheckboxSelect('on_shared_storage') submit_button = Button('Submit') cancel_button = Button('Cancel') @property def is_displayed(self): # Only the instance name is displayed, cannot confirm provider return False
[docs]class MigrateView(CloudInstanceView): @View.nested class form(View): # noqa auto_select = CheckboxSelect('auto_select_host') block_migration = CheckboxSelect('block_migration') disk_overcommit = CheckboxSelect('disk_over_commit') submit_button = Button('Submit') cancel_button = Button('Cancel') @property def is_displayed(self): # Only the instance name is displayed, cannot confirm provider return False
[docs]class ReconfigureView(CloudInstanceView): @View.nested class form(View): # noqa flavor = BootstrapSelect('flavor') submit_button = Button('Submit') cancel_button = Button('Cancel') @property def is_displayed(self): # Only the instance name is displayed, cannot confirm provider return False
@navigator.register(OpenStackInstance, 'AddFloatingIP')
[docs]class AddFloatingIP(CFMENavigateStep): VIEW = AddFloatingIPView prerequisite = NavigateToSibling('Details')
[docs] def step(self): configuration = self.prerequisite_view.toolbar.configuration try: configuration.item_select('Associate a Floating IP with this Instance') except NoSuchElementException: raise DestinationNotFound('Add Floating IP option not available for instance')
@navigator.register(OpenStackInstance, 'RemoveFloatingIP')
[docs]class RemoveFloatingIP(CFMENavigateStep): VIEW = RemoveFloatingIPView prerequisite = NavigateToSibling('Details')
[docs] def step(self): configuration = self.prerequisite_view.toolbar.configuration try: configuration.item_select('Disassociate a Floating IP from this Instance') except NoSuchElementException: raise DestinationNotFound('Remove Floating IP option not available for instance')
@navigator.register(OpenStackInstance, 'AttachVolume')
[docs]class AttachVolume(CFMENavigateStep): VIEW = AttachVolumeView prerequisite = NavigateToSibling('Details')
[docs] def step(self): configuration = self.prerequisite_view.toolbar.configuration try: configuration.item_select('Attach a Cloud Volume to this Instance') except NoSuchElementException: raise DestinationNotFound('Attach Cloud Volume option not available for instance')
@navigator.register(OpenStackInstance, 'DetachVolume')
[docs]class DetachVolume(CFMENavigateStep): VIEW = DetachVolumeView prerequisite = NavigateToSibling('Details')
[docs] def step(self): configuration = self.prerequisite_view.toolbar.configuration try: configuration.item_select('Detach a Cloud Volume from this Instance') except NoSuchElementException: raise DestinationNotFound('Detach Cloud Volume option not available for instance')
@navigator.register(OpenStackInstance, 'Evacuate')
[docs]class Evacuate(CFMENavigateStep): VIEW = EvacuateView prerequisite = NavigateToSibling('Details')
[docs] def step(self): lifecycle = self.prerequisite_view.toolbar.lifecycle try: lifecycle.item_select('Evacuate Instance') except NoSuchElementException: raise DestinationNotFound('Evacuate option not available for instance')
@navigator.register(OpenStackInstance, 'Migrate')
[docs]class Migrate(CFMENavigateStep): VIEW = MigrateView prerequisite = NavigateToSibling('Details')
[docs] def step(self): lifecycle = self.prerequisite_view.toolbar.lifecycle try: lifecycle.item_select('Migrate Instance') except NoSuchElementException: raise DestinationNotFound('Migrate option not available for instance')
@navigator.register(OpenStackInstance, 'Reconfigure')
[docs]class Reconfigure(CFMENavigateStep): VIEW = ReconfigureView prerequisite = NavigateToSibling('Details')
[docs] def step(self): configuration = self.prerequisite_view.toolbar.configuration try: configuration.item_select('Reconfigure this Instance') except NoSuchElementException: raise DestinationNotFound('Reconfigure option not available for instance')
@navigator.register(OpenStackInstance, 'RightSize')
[docs]class RightSize(CFMENavigateStep): VIEW = RightSizeView prerequisite = NavigateToSibling('Details')
[docs] def step(self): configuration = self.prerequisite_view.toolbar.configuration try: configuration.item_select('Right-Size Recommendations') except NoSuchElementException: raise DestinationNotFound('Right Size option not available for instance')