from neutronclient.common.exceptions import PortNotFoundClient
from novaclient.exceptions import NotFound, BadRequest
-from snaps.openstack.create_network import PortSettings
+from snaps.config.vm_inst import VmInstanceConfig, FloatingIpConfig
from snaps.openstack.openstack_creator import OpenStackComputeObject
-from snaps.openstack.utils import glance_utils, cinder_utils
+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'
# Apply floating IPs
for floating_ip_setting in self.instance_settings.floating_ip_settings:
- port = port_dict.get(floating_ip_setting.port_name)
+ self.add_floating_ip(floating_ip_setting)
- if not port:
- raise VmInstanceCreationError(
- 'Cannot find port object with name - ' +
- floating_ip_setting.port_name)
+ def add_floating_ip(self, floating_ip_setting):
+ """
+ Adds a floating IP to a running instance
+ :param floating_ip_setting - the floating IP configuration
+ """
+ port_dict = dict()
+ for key, port in self.__ports:
+ port_dict[key] = port
- # Setup Floating IP only if there is a router with an external
- # gateway
- ext_gateway = self.__ext_gateway_by_router(
- floating_ip_setting.router_name)
- if ext_gateway:
- subnet = neutron_utils.get_subnet(
- self.__neutron,
- subnet_name=floating_ip_setting.subnet_name)
- floating_ip = neutron_utils.create_floating_ip(
- self.__neutron, ext_gateway)
- self.__floating_ip_dict[floating_ip_setting.name] = floating_ip
+ # Apply floating IP
+ port = port_dict.get(floating_ip_setting.port_name)
- logger.info(
- 'Created floating IP %s via router - %s', floating_ip.ip,
- floating_ip_setting.router_name)
- self.__add_floating_ip(floating_ip, port, subnet)
- else:
- raise VmInstanceCreationError(
- 'Unable to add floating IP to port, cannot locate router '
- 'with an external gateway ')
+ if not port:
+ raise VmInstanceCreationError(
+ 'Cannot find port object with name - ' +
+ floating_ip_setting.port_name)
+
+ # Setup Floating IP only if there is a router with an external
+ # gateway
+ ext_gateway = self.__ext_gateway_by_router(
+ floating_ip_setting.router_name)
+ if ext_gateway:
+ subnet = neutron_utils.get_subnet(
+ self.__neutron,
+ subnet_name=floating_ip_setting.subnet_name)
+ floating_ip = neutron_utils.create_floating_ip(
+ self.__neutron, ext_gateway)
+ self.__floating_ip_dict[floating_ip_setting.name] = floating_ip
+
+ logger.info(
+ 'Created floating IP %s via router - %s', floating_ip.ip,
+ floating_ip_setting.router_name)
+ self.__add_floating_ip(floating_ip, port, subnet)
+ else:
+ raise VmInstanceCreationError(
+ 'Unable to add floating IP to port, cannot locate router '
+ 'with an external gateway ')
def __ext_gateway_by_router(self, router_name):
"""
for key, fip in self.__floating_ip_dict.items():
return fip
+ # When cannot be found above
+ if len(self.__floating_ip_dict) > 0:
+ for key, fip in self.__floating_ip_dict.items():
+ return fip
+
def __config_nic(self, nic_name, port, ip):
"""
Although ports/NICs can contain multiple IPs, this code currently only
:param poll_interval: The polling interval in seconds
:return: T/F
"""
- return self.__vm_status_check(STATUS_ACTIVE, block,
- self.instance_settings.vm_boot_timeout,
- poll_interval)
+ if self.__vm_status_check(
+ STATUS_ACTIVE, block, self.instance_settings.vm_boot_timeout,
+ poll_interval):
+ self.__vm = nova_utils.get_server_object_by_id(
+ self._nova, self.__vm.id)
+ return True
+ return False
def __vm_status_check(self, expected_status_code, block, timeout,
poll_interval):
:param fip_name: the name of the floating IP to return
:return: the SSH client or None
"""
- fip = None
if fip_name and self.__floating_ip_dict.get(fip_name):
return self.__floating_ip_dict.get(fip_name)
- if not fip:
+ else:
return self.__get_first_provisioning_floating_ip()
def ssh_client(self, fip_name=None):
self.keypair_settings.private_filepath,
proxy_settings=self._os_creds.proxy_settings)
else:
- logger.warning(
+ FloatingIPAllocationError(
'Cannot return an SSH client. No Floating IP configured')
def add_security_group(self, security_group):
logger.warning('Security group not removed - ' + str(e))
return False
-
-class VmInstanceSettings:
- """
- Class responsible for holding configuration setting for a VM Instance
- """
-
- def __init__(self, **kwargs):
+ def reboot(self, reboot_type=RebootType.soft):
"""
- Constructor
- :param name: the name of the VM
- :param flavor: the VM's flavor name
- :param port_settings: the port configuration settings (required)
- :param security_group_names: a set of names of the security groups to
- add to the VM
- :param floating_ip_settings: the floating IP configuration settings
- :param sudo_user: the sudo user of the VM that will override the
- instance_settings.image_user when trying to
- connect to the VM
- :param vm_boot_timeout: the amount of time a thread will sleep waiting
- for an instance to boot
- :param vm_delete_timeout: the amount of time a thread will sleep
- waiting for an instance to be deleted
- :param ssh_connect_timeout: the amount of time a thread will sleep
- waiting obtaining an SSH connection to a VM
- :param availability_zone: the name of the compute server on which to
- deploy the VM (optional)
- :param volume_names: a list of the names of the volume to attach
- (optional)
- :param userdata: the string contents of any optional cloud-init script
- to execute after the VM has been activated.
- This value may also contain a dict who's key value
- must contain the key 'cloud-init_file' which denotes
- the location of some file containing the cloud-init
- script
- """
- self.name = kwargs.get('name')
- self.flavor = kwargs.get('flavor')
- self.sudo_user = kwargs.get('sudo_user')
- self.userdata = kwargs.get('userdata')
-
- self.port_settings = list()
- port_settings = kwargs.get('ports')
- if not port_settings:
- port_settings = kwargs.get('port_settings')
- if port_settings:
- for port_setting in port_settings:
- if isinstance(port_setting, dict):
- self.port_settings.append(PortSettings(**port_setting))
- elif isinstance(port_setting, PortSettings):
- self.port_settings.append(port_setting)
-
- if kwargs.get('security_group_names'):
- if isinstance(kwargs['security_group_names'], list):
- self.security_group_names = kwargs['security_group_names']
- elif isinstance(kwargs['security_group_names'], set):
- self.security_group_names = kwargs['security_group_names']
- elif isinstance(kwargs['security_group_names'], str):
- self.security_group_names = [kwargs['security_group_names']]
- else:
- raise VmInstanceSettingsError(
- 'Invalid data type for security_group_names attribute')
- else:
- self.security_group_names = set()
-
- self.floating_ip_settings = list()
- floating_ip_settings = kwargs.get('floating_ips')
- if not floating_ip_settings:
- floating_ip_settings = kwargs.get('floating_ip_settings')
- if floating_ip_settings:
- for floating_ip_config in floating_ip_settings:
- if isinstance(floating_ip_config, FloatingIpSettings):
- self.floating_ip_settings.append(floating_ip_config)
- else:
- self.floating_ip_settings.append(FloatingIpSettings(
- **floating_ip_config['floating_ip']))
-
- self.vm_boot_timeout = kwargs.get('vm_boot_timeout', 900)
- self.vm_delete_timeout = kwargs.get('vm_delete_timeout', 300)
- self.ssh_connect_timeout = kwargs.get('ssh_connect_timeout', 180)
- self.availability_zone = kwargs.get('availability_zone')
- self.volume_names = kwargs.get('volume_names')
+ 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)
- if self.volume_names and not isinstance(self.volume_names, list):
- raise VmInstanceSettingsError('volume_names must be a list')
- if not self.name or not self.flavor:
- raise VmInstanceSettingsError(
- 'Instance configuration requires the attributes: name, flavor')
+def generate_creator(os_creds, vm_inst, image_config, keypair_config=None):
+ """
+ Initializes an OpenStackVmInstance object
+ :param os_creds: the OpenStack credentials
+ :param vm_inst: the SNAPS-OO VmInst domain object
+ :param image_config: the associated ImageConfig object
+ :param keypair_config: the associated KeypairConfig object (optional)
+ :return: an initialized OpenStackVmInstance object
+ """
+ nova = nova_utils.nova_client(os_creds)
+ neutron = neutron_utils.neutron_client(os_creds)
+ derived_inst_config = settings_utils.create_vm_inst_config(
+ nova, neutron, vm_inst)
- if len(self.port_settings) == 0:
- raise VmInstanceSettingsError(
- 'Instance configuration requires port settings (aka. NICS)')
+ derived_inst_creator = OpenStackVmInstance(
+ os_creds, derived_inst_config, image_config, keypair_config)
+ derived_inst_creator.initialize()
+ return derived_inst_creator
-class FloatingIpSettings:
+class VmInstanceSettings(VmInstanceConfig):
"""
- Class responsible for holding configuration settings for a floating IP
+ Deprecated, use snaps.config.vm_inst.VmInstanceConfig instead
"""
-
def __init__(self, **kwargs):
- """
- Constructor
- :param name: the name of the floating IP
- :param port_name: the name of the router to the external network
- :param router_name: the name of the router to the external network
- :param subnet_name: the name of the subnet on which to attach the
- floating IP
- :param provisioning: when true, this floating IP can be used for
- provisioning
-
- TODO - provisioning flag is a hack as I have only observed a single
- Floating IPs that actually works on an instance. Multiple floating IPs
- placed on different subnets from the same port are especially
- troublesome as you cannot predict which one will actually connect.
- For now, it is recommended not to setup multiple floating IPs on an
- instance unless absolutely necessary.
- """
- self.name = kwargs.get('name')
- self.port_name = kwargs.get('port_name')
- self.port_id = kwargs.get('port_id')
- self.router_name = kwargs.get('router_name')
- self.subnet_name = kwargs.get('subnet_name')
- if kwargs.get('provisioning') is not None:
- self.provisioning = kwargs['provisioning']
- else:
- self.provisioning = True
-
- # if not self.name or not self.port_name or not self.router_name:
- if not self.name or not self.router_name:
- raise FloatingIpSettingsError(
- 'The attributes name, port_name and router_name are required')
-
- if not self.port_name and not self.port_id:
- raise FloatingIpSettingsError(
- 'The attributes port_name or port_id are required')
+ from warnings import warn
+ warn('Use snaps.config.vm_inst.VmInstanceConfig instead',
+ DeprecationWarning)
+ super(self.__class__, self).__init__(**kwargs)
-class VmInstanceSettingsError(Exception):
+class FloatingIpSettings(FloatingIpConfig):
"""
- Exception to be thrown when an VM instance settings are incorrect
+ Deprecated, use snaps.config.vm_inst.FloatingIpConfig instead
"""
+ def __init__(self, **kwargs):
+ from warnings import warn
+ warn('Use snaps.config.vm_inst.FloatingIpConfig instead',
+ DeprecationWarning)
+ super(self.__class__, self).__init__(**kwargs)
-class FloatingIpSettingsError(Exception):
+class VmInstanceCreationError(Exception):
"""
- Exception to be thrown when an VM instance settings are incorrect
+ Exception to be thrown when an VM instance cannot be created
"""
-class VmInstanceCreationError(Exception):
+class FloatingIPAllocationError(Exception):
"""
- Exception to be thrown when an VM instance cannot be created
+ Exception to be thrown when an VM instance cannot allocate a floating IP
"""