Adam Litke has uploaded a new change for review. Change subject: Move VM operations into a mixin for reusability ......................................................................
Move VM operations into a mixin for reusability The plugin in runvm.py has lots of useful logic for manipulating the hosted engine VM. This logic can be very useful to other plugins (eg. health.py) that may want to offer the user assistance with managing the VM. This patch moves the VM logic into a separate class that can be mixed in with any other plugin which may want the functionality. Signed-off-by: Adam Litke <ali...@redhat.com> Related-To: https://bugzilla.redhat.com/1034788 Change-Id: I811f6712cb5c9324c6a3acca0bfc5bc9195b25ef --- M src/ovirt_hosted_engine_setup/Makefile.am A src/ovirt_hosted_engine_setup/mixins.py M src/plugins/ovirt-hosted-engine-setup/vm/runvm.py 3 files changed, 218 insertions(+), 185 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-hosted-engine-setup refs/changes/26/23926/1 diff --git a/src/ovirt_hosted_engine_setup/Makefile.am b/src/ovirt_hosted_engine_setup/Makefile.am index f7925a9..0a986b4 100644 --- a/src/ovirt_hosted_engine_setup/Makefile.am +++ b/src/ovirt_hosted_engine_setup/Makefile.am @@ -44,6 +44,7 @@ set_maintenance.py \ tasks.py \ vm_status.py \ + mixins.py \ $(NULL) nodist_ovirthostedenginelib_PYTHON = \ diff --git a/src/ovirt_hosted_engine_setup/mixins.py b/src/ovirt_hosted_engine_setup/mixins.py new file mode 100644 index 0000000..7cd8d87 --- /dev/null +++ b/src/ovirt_hosted_engine_setup/mixins.py @@ -0,0 +1,213 @@ +# +# ovirt-hosted-engine-setup -- ovirt hosted engine setup +# Copyright (C) 2013 Red Hat, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +"""VM Utils""" + +import string +import random +import gettext +import time + +from ovirt_hosted_engine_setup import constants as ohostedcons +from ovirt_hosted_engine_setup import tasks + + +_ = lambda m: gettext.dgettext(message=m, domain='ovirt-hosted-engine-setup') + + +class VmOperations(object): + """ + Hosted engine VM manipulation features for otopi Plugin objects + """ + + TICKET_MAX_TRIES = 10 + TICKET_DELAY = 1 + POWEROFF_CHECK_INTERVALL = 1 + + def _generateTempVncPassword(self): + self.logger.info( + _('Generating a temporary VNC password.') + ) + return '%s%s' % ( + ''.join([random.choice(string.digits) for _i in range(4)]), + ''.join([random.choice(string.letters) for _i in range(4)]), + ) + + def _generateUserMessage(self, console_type): + displayPort = 5900 + displaySecurePort = 5901 + serv = self.environment[ohostedcons.VDSMEnv.VDS_CLI] + try: + stats = serv.s.getVmStats( + self.environment[ohostedcons.VMEnv.VM_UUID] + ) + self.logger.debug(stats) + if not stats['status']['code'] == 0: + self.logger.error(stats['status']['message']) + else: + statsList = stats['statsList'][0] + displaySecurePort = statsList['displaySecurePort'] + displayPort = statsList['displayPort'] + except Exception: + self.logger.debug( + 'Error getting VM stats', + exc_info=True, + ) + if console_type == 'vnc': + return _( + 'You can now connect to the VM with the following command:\n' + '\t{remote} vnc://localhost:{displayPort}\n' + 'Use temporary password "{password}" ' + 'to connect to vnc console.\n' + ).format( + remote=self.command.get('remote-viewer'), + password=self.environment[ + ohostedcons.VMEnv.VM_PASSWD + ], + displayPort=displayPort + ) + elif console_type == 'qxl': + if displaySecurePort < 0: + displaySecurePort = displayPort + return _( + 'You can now connect to the VM with the following command:\n' + '\t{remote} --spice-ca-file={ca_cert} ' + 'spice://localhost?tls-port={displaySecurePort} ' + '--spice-host-subject="{subject}"\nUse temporary password ' + '"{password}" to connect to spice console.' + ).format( + remote=self.command.get('remote-viewer'), + ca_cert=ohostedcons.FileLocations.LIBVIRT_CA_CERT, + subject=self.environment[ohostedcons.VDSMEnv.SPICE_SUBJECT], + password=self.environment[ + ohostedcons.VMEnv.VM_PASSWD + ], + displaySecurePort=displaySecurePort + ) + + else: + raise RuntimeError( + _( + 'Unsuppored console type "{console}" requested'.format( + console=console_type + ) + ) + ) + + def _create_vm(self): + if not self._wait_vm_destroyed(): + self.logger.warning( + _( + 'The Hosted Engine VM has been found still powered on:\n' + 'please turn it off using "hosted-engine --vm-poweroff".\n' + 'The system will wait until the VM is powered off.' + ) + ) + while not self._wait_vm_destroyed(): + time.sleep(self.POWEROFF_CHECK_INTERVALL) + + self.logger.info(_('Creating VM')) + cmd = self._vdscommand + [ + 'create', + ohostedcons.FileLocations.ENGINE_VM_CONF, + ] + self.execute( + cmd, + raiseOnError=True + ) + password_set = False + tries = self.TICKET_MAX_TRIES + while not password_set and tries > 0: + tries -= 1 + try: + cmd = self._vdscommand + [ + 'setVmTicket', + self.environment[ohostedcons.VMEnv.VM_UUID], + self.environment[ohostedcons.VMEnv.VM_PASSWD], + self.environment[ + ohostedcons.VMEnv.VM_PASSWD_VALIDITY_SECS + ], + ] + self.execute( + cmd, + raiseOnError=True + ) + password_set = True + except RuntimeError as e: + self.logger.debug(str(e)) + time.sleep(self.TICKET_DELAY) + if not password_set: + raise RuntimeError( + _( + 'Cannot set temporary password for console connection.\n' + 'The VM may not have been created: please check VDSM logs' + ) + ) + else: + self.dialog.note( + self._generateUserMessage( + self.environment[ + ohostedcons.VMEnv.CONSOLE_TYPE + ] + ) + ) + host = 'localhost' + spice_values = [ + x.strip() + for x in self.environment[ + ohostedcons.VDSMEnv.SPICE_SUBJECT + ].split(',') + if x + ] + for items in spice_values: + key, val = items.split('=', 1) + if key == 'CN': + host = val + break + + self.dialog.note( + _( + 'Please note that in order to use remote-viewer you need ' + 'to be able to run graphical applications.\n' + 'This means that if you are using ssh you have to supply ' + 'the -Y flag (enables trusted X11 forwarding).\n' + 'Otherwise you can run the command from a terminal in ' + 'your preferred desktop environment.\n' + 'If you cannot run graphical applications you can ' + 'connect to the graphic console from another host or ' + 'connect to the console using the following command:\n' + 'virsh -c qemu+tls://{host}/system console HostedEngine' + ).format( + host=host + ) + ) + self.dialog.note( + _( + 'If you need to reboot the VM you will need to start it ' + 'manually using the command:\n' + 'hosted-engine --vm-start\n' + 'You can then set a temporary password using ' + 'the command:\n' + 'hosted-engine --add-console-password' + ) + ) + + def _wait_vm_destroyed(self): + waiter = tasks.VMDownWaiter(self.environment) + return waiter.wait() diff --git a/src/plugins/ovirt-hosted-engine-setup/vm/runvm.py b/src/plugins/ovirt-hosted-engine-setup/vm/runvm.py index 33fa037..d5eebf1 100644 --- a/src/plugins/ovirt-hosted-engine-setup/vm/runvm.py +++ b/src/plugins/ovirt-hosted-engine-setup/vm/runvm.py @@ -23,208 +23,27 @@ """ -import string -import random import gettext -import time - from otopi import util from otopi import plugin - from ovirt_hosted_engine_setup import constants as ohostedcons -from ovirt_hosted_engine_setup import tasks +from ovirt_hosted_engine_setup import mixins _ = lambda m: gettext.dgettext(message=m, domain='ovirt-hosted-engine-setup') @util.export -class Plugin(plugin.PluginBase): +class Plugin(mixins.VmOperations, plugin.PluginBase): """ VM configuration plugin. """ - TICKET_MAX_TRIES = 10 - TICKET_DELAY = 1 - POWEROFF_CHECK_INTERVALL = 1 - def __init__(self, context): super(Plugin, self).__init__(context=context) self._vdscommand = [] - - def _generateTempVncPassword(self): - self.logger.info( - _('Generating a temporary VNC password.') - ) - return '%s%s' % ( - ''.join([random.choice(string.digits) for _i in range(4)]), - ''.join([random.choice(string.letters) for _i in range(4)]), - ) - - def _generateUserMessage(self, console_type): - displayPort = 5900 - displaySecurePort = 5901 - serv = self.environment[ohostedcons.VDSMEnv.VDS_CLI] - try: - stats = serv.s.getVmStats( - self.environment[ohostedcons.VMEnv.VM_UUID] - ) - self.logger.debug(stats) - if not stats['status']['code'] == 0: - self.logger.error(stats['status']['message']) - else: - statsList = stats['statsList'][0] - displaySecurePort = statsList['displaySecurePort'] - displayPort = statsList['displayPort'] - except Exception: - self.logger.debug( - 'Error getting VM stats', - exc_info=True, - ) - if console_type == 'vnc': - return _( - 'You can now connect to the VM with the following command:\n' - '\t{remote} vnc://localhost:{displayPort}\n' - 'Use temporary password "{password}" ' - 'to connect to vnc console.\n' - ).format( - remote=self.command.get('remote-viewer'), - password=self.environment[ - ohostedcons.VMEnv.VM_PASSWD - ], - displayPort=displayPort - ) - elif console_type == 'qxl': - if displaySecurePort < 0: - displaySecurePort = displayPort - return _( - 'You can now connect to the VM with the following command:\n' - '\t{remote} --spice-ca-file={ca_cert} ' - 'spice://localhost?tls-port={displaySecurePort} ' - '--spice-host-subject="{subject}"\nUse temporary password ' - '"{password}" to connect to spice console.' - ).format( - remote=self.command.get('remote-viewer'), - ca_cert=ohostedcons.FileLocations.LIBVIRT_CA_CERT, - subject=self.environment[ohostedcons.VDSMEnv.SPICE_SUBJECT], - password=self.environment[ - ohostedcons.VMEnv.VM_PASSWD - ], - displaySecurePort=displaySecurePort - ) - - else: - raise RuntimeError( - _( - 'Unsuppored console type "{console}" requested'.format( - console=console_type - ) - ) - ) - - def _create(self): - if not self._wait_vm_destroyed(): - self.logger.warning( - _( - 'The Hosted Engine VM has been found still powered on:\n' - 'please turn it off using "hosted-engine --vm-poweroff".\n' - 'The system will wait until the VM is powered off.' - ) - ) - while not self._wait_vm_destroyed(): - time.sleep(self.POWEROFF_CHECK_INTERVALL) - - self.logger.info(_('Creating VM')) - cmd = self._vdscommand + [ - 'create', - ohostedcons.FileLocations.ENGINE_VM_CONF, - ] - self.execute( - cmd, - raiseOnError=True - ) - password_set = False - tries = self.TICKET_MAX_TRIES - while not password_set and tries > 0: - tries -= 1 - try: - cmd = self._vdscommand + [ - 'setVmTicket', - self.environment[ohostedcons.VMEnv.VM_UUID], - self.environment[ohostedcons.VMEnv.VM_PASSWD], - self.environment[ - ohostedcons.VMEnv.VM_PASSWD_VALIDITY_SECS - ], - ] - self.execute( - cmd, - raiseOnError=True - ) - password_set = True - except RuntimeError as e: - self.logger.debug(str(e)) - time.sleep(self.TICKET_DELAY) - if not password_set: - raise RuntimeError( - _( - 'Cannot set temporary password for console connection.\n' - 'The VM may not have been created: please check VDSM logs' - ) - ) - else: - self.dialog.note( - self._generateUserMessage( - self.environment[ - ohostedcons.VMEnv.CONSOLE_TYPE - ] - ) - ) - host = 'localhost' - spice_values = [ - x.strip() - for x in self.environment[ - ohostedcons.VDSMEnv.SPICE_SUBJECT - ].split(',') - if x - ] - for items in spice_values: - key, val = items.split('=', 1) - if key == 'CN': - host = val - break - - self.dialog.note( - _( - 'Please note that in order to use remote-viewer you need ' - 'to be able to run graphical applications.\n' - 'This means that if you are using ssh you have to supply ' - 'the -Y flag (enables trusted X11 forwarding).\n' - 'Otherwise you can run the command from a terminal in ' - 'your preferred desktop environment.\n' - 'If you cannot run graphical applications you can ' - 'connect to the graphic console from another host or ' - 'connect to the console using the following command:\n' - 'virsh -c qemu+tls://{host}/system console HostedEngine' - ).format( - host=host - ) - ) - self.dialog.note( - _( - 'If you need to reboot the VM you will need to start it ' - 'manually using the command:\n' - 'hosted-engine --vm-start\n' - 'You can then set a temporary password using ' - 'the command:\n' - 'hosted-engine --add-console-password' - ) - ) - - def _wait_vm_destroyed(self): - waiter = tasks.VMDownWaiter(self.environment) - return waiter.wait() @plugin.event( stage=plugin.Stages.STAGE_INIT, @@ -325,7 +144,7 @@ #connect from remote. os_installed = False while not os_installed: - self._create() + self._create_vm() self.dialog.note( _( 'Please install the OS on the VM.\n' @@ -386,7 +205,7 @@ ], ) def _boot_from_hd(self): - self._create() + self._create_vm() # vim: expandtab tabstop=4 shiftwidth=4 -- To view, visit http://gerrit.ovirt.org/23926 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I811f6712cb5c9324c6a3acca0bfc5bc9195b25ef Gerrit-PatchSet: 1 Gerrit-Project: ovirt-hosted-engine-setup Gerrit-Branch: ovirt-hosted-engine-setup-1.0 Gerrit-Owner: Adam Litke <ali...@redhat.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches