From e2f708a2527816a845ca1048f5ad5c58fdb506e0 Mon Sep 17 00:00:00 2001 From: spisarski Date: Fri, 1 Dec 2017 11:06:23 -0700 Subject: Added the ability to reboot OpenStack server instances JIRA: SNAPS-243 Change-Id: I7232ee14cac81d39d86e7391a4e006b8276ed536 Signed-off-by: spisarski --- docs/how-to-use/IntegrationTests.rst | 3 ++ snaps/openstack/create_instance.py | 12 ++++++ snaps/openstack/tests/create_instance_tests.py | 58 ++++++++++++++++++++++++++ snaps/openstack/utils/nova_utils.py | 31 ++++++++++++++ 4 files changed, 104 insertions(+) diff --git a/docs/how-to-use/IntegrationTests.rst b/docs/how-to-use/IntegrationTests.rst index a11afb9..df8859f 100644 --- a/docs/how-to-use/IntegrationTests.rst +++ b/docs/how-to-use/IntegrationTests.rst @@ -548,6 +548,9 @@ create_instance_tests.py - CreateInstanceSingleNetworkTests | test_ssh_client_fip_reverse_engineer | Nova 2 | Ensures that an instance can be reverse engineered and | | | Neutron 2 | allows for a floating IP to be added after initialization | +---------------------------------------+---------------+-----------------------------------------------------------+ +| test_ssh_client_fip_after_reboot | Nova 2 | Ensures that an instance can be reached over SSH after | +| | Neutron 2 | a reboot call has been issued | ++---------------------------------------+---------------+-----------------------------------------------------------+ | test_ssh_client_fip_second_creator | Nova 2 | Ensures that an instance can be reached over SSH via a | | | Neutron 2 | second identical creator object | +---------------------------------------+---------------+-----------------------------------------------------------+ diff --git a/snaps/openstack/create_instance.py b/snaps/openstack/create_instance.py index d7300e6..0105ef0 100644 --- a/snaps/openstack/create_instance.py +++ b/snaps/openstack/create_instance.py @@ -23,6 +23,7 @@ from snaps.openstack.openstack_creator import OpenStackComputeObject from snaps.openstack.utils import glance_utils, cinder_utils, settings_utils from snaps.openstack.utils import neutron_utils from snaps.openstack.utils import nova_utils +from snaps.openstack.utils.nova_utils import RebootType from snaps.provisioning import ansible_utils __author__ = 'spisarski' @@ -787,6 +788,17 @@ class OpenStackVmInstance(OpenStackComputeObject): logger.warning('Security group not removed - ' + str(e)) return False + def reboot(self, reboot_type=RebootType.soft): + """ + Issues a reboot call + :param reboot_type: instance of + snaps.openstack.utils.nova_utils.RebootType + enumeration + :return: + """ + nova_utils.reboot_server( + self._nova, self.__vm, reboot_type=reboot_type) + def generate_creator(os_creds, vm_inst, image_config, keypair_config=None): """ diff --git a/snaps/openstack/tests/create_instance_tests.py b/snaps/openstack/tests/create_instance_tests.py index 1721ce3..6eb21b5 100644 --- a/snaps/openstack/tests/create_instance_tests.py +++ b/snaps/openstack/tests/create_instance_tests.py @@ -48,6 +48,8 @@ from snaps.openstack.create_volume import OpenStackVolume from snaps.openstack.tests import openstack_tests, validation_utils from snaps.openstack.tests.os_source_file_test import ( OSIntegrationTestCase, OSComponentTestCase) +from snaps.openstack.utils import nova_utils +from snaps.openstack.utils.nova_utils import RebootType from snaps.openstack.utils import nova_utils, settings_utils, neutron_utils __author__ = 'spisarski' @@ -765,6 +767,62 @@ class CreateInstanceSingleNetworkTests(OSIntegrationTestCase): self.assertTrue(validate_ssh_client(inst_creator)) + def test_ssh_client_fip_after_reboot(self): + """ + Tests the ability to access a VM via SSH and a floating IP after it has + been rebooted. + """ + port_settings = PortConfig( + name=self.port_1_name, + network_name=self.pub_net_config.network_settings.name) + + instance_settings = VmInstanceConfig( + name=self.vm_inst_name, + flavor=self.flavor_creator.flavor_settings.name, + port_settings=[port_settings], + security_group_names=[self.sec_grp_creator.sec_grp_settings.name], + floating_ip_settings=[FloatingIpConfig( + name=self.floating_ip_name, port_name=self.port_1_name, + router_name=self.pub_net_config.router_settings.name)]) + + inst_creator = OpenStackVmInstance( + self.os_creds, instance_settings, + self.image_creator.image_settings, + keypair_settings=self.keypair_creator.keypair_settings) + self.inst_creators.append(inst_creator) + + # block=True will force the create() method to block until the + vm_inst = inst_creator.create(block=True) + self.assertIsNotNone(vm_inst) + + self.assertTrue(inst_creator.vm_active(block=True)) + + ip = inst_creator.get_port_ip(port_settings.name) + self.assertTrue(check_dhcp_lease(inst_creator, ip)) + + self.assertEqual(vm_inst.id, inst_creator.get_vm_inst().id) + + self.assertTrue(validate_ssh_client(inst_creator)) + + # Test default reboot which should be 'SOFT' + inst_creator.reboot() + # Lag time to allow for shutdown routine to take effect + time.sleep(10) + self.assertTrue(check_dhcp_lease(inst_creator, ip)) + self.assertTrue(validate_ssh_client(inst_creator)) + + # Test 'SOFT' reboot + inst_creator.reboot(reboot_type=RebootType.soft) + time.sleep(10) + self.assertTrue(check_dhcp_lease(inst_creator, ip)) + self.assertTrue(validate_ssh_client(inst_creator)) + + # Test 'HARD' reboot + inst_creator.reboot(reboot_type=RebootType.hard) + time.sleep(10) + self.assertTrue(check_dhcp_lease(inst_creator, ip)) + self.assertTrue(validate_ssh_client(inst_creator)) + def test_ssh_client_fip_after_init(self): """ Tests the ability to assign a floating IP to an already initialized diff --git a/snaps/openstack/utils/nova_utils.py b/snaps/openstack/utils/nova_utils.py index b735ee2..2d569e6 100644 --- a/snaps/openstack/utils/nova_utils.py +++ b/snaps/openstack/utils/nova_utils.py @@ -15,6 +15,7 @@ import logging +import enum import os import time from cryptography.hazmat.backends import default_backend @@ -281,6 +282,21 @@ def get_server_info(nova, server): return vm._info return None +def reboot_server(nova, server, reboot_type=None): + """ + Returns a dictionary of a VMs info as returned by OpenStack + :param nova: the Nova client + :param server: the old server object + :param reboot_type: Acceptable values 'SOFT', 'HARD' + (api uses SOFT as the default) + :return: a dict of the info if VM exists else None + """ + vm = __get_latest_server_os_object(nova, server) + if vm: + vm.reboot(reboot_type=reboot_type.value) + else: + raise ServerNotFoundError('Cannot locate server') + def create_keys(key_size=2048): """ @@ -730,7 +746,22 @@ def detach_volume(nova, server, volume, timeout=None): return get_server_object_by_id(nova, server.id) +class RebootType(enum.Enum): + """ + A rule's direction + """ + soft = 'SOFT' + hard = 'HARD' + + class NovaException(Exception): """ Exception when calls to the Keystone client cannot be served properly """ + + +class ServerNotFoundError(Exception): + """ + Exception when operations to a VM/Server is requested and the OpenStack + Server instance cannot be located + """ -- cgit 1.2.3-korg