1 # Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
2 # and others. All rights reserved.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
18 from neutronclient.common.exceptions import PortNotFoundClient
19 from novaclient.exceptions import NotFound, BadRequest
21 from snaps.openstack.create_network import PortSettings
22 from snaps.openstack.openstack_creator import OpenStackComputeObject
23 from snaps.openstack.utils import glance_utils, cinder_utils
24 from snaps.openstack.utils import neutron_utils
25 from snaps.openstack.utils import nova_utils
26 from snaps.provisioning import ansible_utils
28 __author__ = 'spisarski'
30 logger = logging.getLogger('create_instance')
33 STATUS_ACTIVE = 'ACTIVE'
34 STATUS_DELETED = 'DELETED'
37 class OpenStackVmInstance(OpenStackComputeObject):
39 Class responsible for managing a VM instance in OpenStack
42 def __init__(self, os_creds, instance_settings, image_settings,
43 keypair_settings=None):
46 :param os_creds: The connection credentials to the OpenStack API
47 :param instance_settings: Contains the settings for this VM
48 :param image_settings: The OpenStack image object settings
49 :param keypair_settings: The keypair metadata (Optional)
52 super(self.__class__, self).__init__(os_creds)
56 self.instance_settings = instance_settings
57 self.image_settings = image_settings
58 self.keypair_settings = keypair_settings
60 self.__floating_ip_dict = dict()
62 # Instantiated in self.create()
65 # Note: this object does not change after the VM becomes active
70 Loads the existing VMInst, Port, FloatingIps
71 :return: VMInst domain object
73 super(self.__class__, self).initialize()
75 self.__neutron = neutron_utils.neutron_client(self._os_creds)
77 self.__ports = self.__query_ports(self.instance_settings.port_settings)
78 self.__lookup_existing_vm_by_name()
80 def create(self, block=False):
82 Creates a VM instance and associated objects unless they already exist
83 :param block: Thread will block until instance has either become
84 active, error, or timeout waiting.
85 Additionally, when True, floating IPs will not be applied
87 :return: VMInst domain object
91 if len(self.__ports) == 0:
92 self.__ports = self.__create_ports(
93 self.instance_settings.port_settings)
95 self.__create_vm(block)
99 def __lookup_existing_vm_by_name(self):
101 Populates the member variables 'self.vm' and 'self.floating_ips' if a
102 VM with the same name already exists
105 server = nova_utils.get_server(
106 self._nova, vm_inst_settings=self.instance_settings)
108 if server.name == self.instance_settings.name:
111 'Found existing machine with name - %s',
112 self.instance_settings.name)
114 fips = neutron_utils.get_floating_ips(self.__neutron,
116 for port_id, fip in fips:
117 settings = self.instance_settings.floating_ip_settings
118 for fip_setting in settings:
119 if port_id == fip_setting.port_id:
120 self.__floating_ip_dict[fip_setting.name] = fip
122 port = neutron_utils.get_port_by_id(
123 self.__neutron, port_id)
124 if port and port.name == fip_setting.port_name:
125 self.__floating_ip_dict[fip_setting.name] = fip
127 def __create_vm(self, block=False):
129 Responsible for creating the VM instance
130 :param block: Thread will block until instance has either become
131 active, error, or timeout waiting. Floating IPs will be
132 assigned after active when block=True
134 glance = glance_utils.glance_client(self._os_creds)
135 self.__vm = nova_utils.create_server(
136 self._nova, self.__neutron, glance, self.instance_settings,
137 self.image_settings, self.keypair_settings)
138 logger.info('Created instance with name - %s',
139 self.instance_settings.name)
142 if not self.vm_active(block=True):
143 raise VmInstanceCreationError(
144 'Fatal error, VM did not become ACTIVE within the alloted '
147 # Create server should do this but found it needed to occur here
148 for sec_grp_name in self.instance_settings.security_group_names:
149 if self.vm_active(block=True):
150 nova_utils.add_security_group(self._nova, self.__vm,
153 raise VmInstanceCreationError(
154 'Cannot applying security group with name ' +
156 ' to VM that did not activate with name - ' +
157 self.instance_settings.name)
159 if self.instance_settings.volume_names:
160 for volume_name in self.instance_settings.volume_names:
161 cinder = cinder_utils.cinder_client(self._os_creds)
162 volume = cinder_utils.get_volume(
163 cinder, volume_name=volume_name)
165 if volume and self.vm_active(block=True):
167 vm = nova_utils.attach_volume(
168 self._nova, self.__vm, volume, timeout)
173 logger.warn('Volume [%s] not attached within timeout '
174 'of [%s]', volume.name, timeout)
176 logger.warn('Unable to attach volume named [%s]',
179 self.__apply_floating_ips()
181 def __apply_floating_ips(self):
183 Applies the configured floating IPs to the necessary ports
186 for key, port in self.__ports:
187 port_dict[key] = port
190 for floating_ip_setting in self.instance_settings.floating_ip_settings:
191 port = port_dict.get(floating_ip_setting.port_name)
194 raise VmInstanceCreationError(
195 'Cannot find port object with name - ' +
196 floating_ip_setting.port_name)
198 # Setup Floating IP only if there is a router with an external
200 ext_gateway = self.__ext_gateway_by_router(
201 floating_ip_setting.router_name)
203 subnet = neutron_utils.get_subnet(
205 subnet_name=floating_ip_setting.subnet_name)
206 floating_ip = neutron_utils.create_floating_ip(
207 self.__neutron, ext_gateway)
208 self.__floating_ip_dict[floating_ip_setting.name] = floating_ip
211 'Created floating IP %s via router - %s', floating_ip.ip,
212 floating_ip_setting.router_name)
213 self.__add_floating_ip(floating_ip, port, subnet)
215 raise VmInstanceCreationError(
216 'Unable to add floating IP to port, cannot locate router '
217 'with an external gateway ')
219 def __ext_gateway_by_router(self, router_name):
221 Returns network name for the external network attached to a router or
223 :param router_name: The name of the router to lookup
224 :return: the external network name or None
226 router = neutron_utils.get_router(
227 self.__neutron, router_name=router_name)
228 if router and router.external_network_id:
229 network = neutron_utils.get_network_by_id(
230 self.__neutron, router.external_network_id)
237 Destroys the VM instance
240 # Cleanup floating IPs
241 for name, floating_ip in self.__floating_ip_dict.items():
243 logger.info('Deleting Floating IP - ' + floating_ip.ip)
244 neutron_utils.delete_floating_ip(self.__neutron, floating_ip)
245 except Exception as e:
246 logger.error('Error deleting Floating IP - ' + str(e))
247 self.__floating_ip_dict = dict()
250 for volume_rec in self.__vm.volume_ids:
251 cinder = cinder_utils.cinder_client(self._os_creds)
252 volume = cinder_utils.get_volume_by_id(cinder, volume_rec['id'])
255 vm = nova_utils.detach_volume(
256 self._nova, self.__vm, volume, 30)
261 'Timeout waiting to detach volume %s', volume.name)
262 except Exception as e:
263 logger.error('Unexpected error detaching volume %s '
264 'with error %s', volume.name, e)
266 logger.warn('Unable to detach volume with ID - [%s]',
270 for name, port in self.__ports:
271 logger.info('Deleting Port with ID - %s ', port.id)
273 neutron_utils.delete_port(self.__neutron, port)
274 except PortNotFoundClient as e:
275 logger.warning('Unexpected error deleting port - %s', e)
277 self.__ports = list()
283 'Deleting VM instance - ' + self.instance_settings.name)
284 nova_utils.delete_vm_instance(self._nova, self.__vm)
285 except Exception as e:
286 logger.error('Error deleting VM - %s', e)
288 # Block until instance cannot be found or returns the status of
290 logger.info('Checking deletion status')
293 if self.vm_deleted(block=True):
295 'VM has been properly deleted VM with name - %s',
296 self.instance_settings.name)
300 'VM not deleted within the timeout period of %s '
301 'seconds', self.instance_settings.vm_delete_timeout)
302 except Exception as e:
304 'Unexpected error while checking VM instance status - %s',
307 def __query_ports(self, port_settings):
309 Returns the previously configured ports or an empty list if none
311 :param port_settings: A list of PortSetting objects
312 :return: a list of OpenStack port tuples where the first member is the
313 port name and the second is the port object
317 for port_setting in port_settings:
318 port = neutron_utils.get_port(
319 self.__neutron, port_settings=port_setting)
321 ports.append((port_setting.name, port))
325 def __create_ports(self, port_settings):
327 Returns the previously configured ports or creates them if they do not
329 :param port_settings: A list of PortSetting objects
330 :return: a list of OpenStack port tuples where the first member is the
331 port name and the second is the port object
335 for port_setting in port_settings:
336 port = neutron_utils.get_port(
337 self.__neutron, port_settings=port_setting)
339 port = neutron_utils.create_port(
340 self.__neutron, self._os_creds, port_setting)
342 ports.append((port_setting.name, port))
346 def __add_floating_ip(self, floating_ip, port, subnet, timeout=30,
347 poll_interval=POLL_INTERVAL):
349 Returns True when active else False
350 TODO - Make timeout and poll_interval configurable...
355 # Take IP of subnet if there is one configured on which to place
357 for fixed_ip in port.ips:
358 if fixed_ip['subnet_id'] == subnet.id:
359 ip = fixed_ip['ip_address']
362 # Simply take the first
363 ip = port.ips[0]['ip_address']
366 count = timeout / poll_interval
368 logger.debug('Attempting to add floating IP to instance')
370 nova_utils.add_floating_ip_to_server(
371 self._nova, self.__vm, floating_ip, ip)
373 'Added floating IP %s to port IP %s on instance %s',
374 floating_ip.ip, ip, self.instance_settings.name)
376 except BadRequest as bre:
377 logger.error('Cannot add floating IP [%s]', bre)
379 except Exception as e:
381 'Retry adding floating IP to instance. Last attempt '
382 'failed with - %s', e)
383 time.sleep(poll_interval)
387 raise VmInstanceCreationError(
388 'Unable find IP address on which to place the floating IP')
390 logger.error('Timeout attempting to add the floating IP to instance.')
391 raise VmInstanceCreationError(
392 'Timeout while attempting add floating IP to instance')
394 def get_os_creds(self):
396 Returns the OpenStack credentials used to create these objects
397 :return: the credentials
399 return self._os_creds
401 def get_vm_inst(self):
403 Returns the latest version of this server object from OpenStack
404 :return: Server object
406 return nova_utils.get_server_object_by_id(self._nova, self.__vm.id)
408 def get_console_output(self):
410 Returns the vm console object for parsing logs
411 :return: the console output object
413 return nova_utils.get_server_console_output(self._nova, self.__vm)
415 def get_port_ip(self, port_name, subnet_name=None):
417 Returns the first IP for the port corresponding with the port_name
418 parameter when subnet_name is None else returns the IP address that
419 corresponds to the subnet_name parameter
420 :param port_name: the name of the port from which to return the IP
421 :param subnet_name: the name of the subnet attached to this IP
422 :return: the IP or None if not found
424 port = self.get_port_by_name(port_name)
427 subnet = neutron_utils.get_subnet(
428 self.__neutron, subnet_name=subnet_name)
430 logger.warning('Cannot retrieve port IP as subnet could '
431 'not be located with name - %s',
434 for fixed_ip in port.ips:
435 if fixed_ip['subnet_id'] == subnet.id:
436 return fixed_ip['ip_address']
438 if port.ips and len(port.ips) > 0:
439 return port.ips[0]['ip_address']
442 def get_port_mac(self, port_name):
444 Returns the first IP for the port corresponding with the port_name
446 TODO - Add in the subnet as an additional parameter as a port may have
448 :param port_name: the name of the port from which to return the IP
449 :return: the IP or None if not found
451 port = self.get_port_by_name(port_name)
453 return port.mac_address
456 def get_port_by_name(self, port_name):
458 Retrieves the OpenStack port object by its given name
459 :param port_name: the name of the port
460 :return: the OpenStack port object or None if not exists
462 for key, port in self.__ports:
465 logger.warning('Cannot find port with name - ' + port_name)
468 def get_vm_info(self):
470 Returns a dictionary of a VMs info as returned by OpenStack
473 return nova_utils.get_server_info(self._nova, self.__vm)
475 def config_nics(self):
477 Responsible for configuring NICs on RPM systems where the instance has
478 more than one configured port
479 :return: the value returned by ansible_utils.apply_ansible_playbook()
481 if len(self.__ports) > 1 and len(self.__floating_ip_dict) > 0:
482 if self.vm_active(block=True) and self.vm_ssh_active(block=True):
483 for key, port in self.__ports:
484 port_index = self.__ports.index((key, port))
486 nic_name = 'eth' + repr(port_index)
487 retval = self.__config_nic(
489 self.__get_first_provisioning_floating_ip().ip)
490 logger.info('Configured NIC - %s on VM - %s',
491 nic_name, self.instance_settings.name)
494 def __get_first_provisioning_floating_ip(self):
496 Returns the first floating IP tagged with the Floating IP name if
497 exists else the first one found
500 for floating_ip_setting in self.instance_settings.floating_ip_settings:
501 if floating_ip_setting.provisioning:
502 fip = self.__floating_ip_dict.get(floating_ip_setting.name)
505 elif len(self.__floating_ip_dict) > 0:
506 for key, fip in self.__floating_ip_dict.items():
509 def __config_nic(self, nic_name, port, ip):
511 Although ports/NICs can contain multiple IPs, this code currently only
514 :param nic_name: Name of the interface
515 :param port: The port information containing the expected IP values.
516 :param ip: The IP on which to apply the playbook.
517 :return: the return value from ansible
519 port_ip = port.ips[0]['ip_address']
522 'nic_name': nic_name,
526 if self.image_settings.nic_config_pb_loc and self.keypair_settings:
527 return self.apply_ansible_playbook(
528 self.image_settings.nic_config_pb_loc, variables)
531 'VM %s cannot self configure NICs eth1++. No playbook or '
532 'keypairs found.', self.instance_settings.name)
534 def apply_ansible_playbook(self, pb_file_loc, variables=None,
537 Applies a playbook to a VM
538 :param pb_file_loc: the file location of the playbook to be applied
539 :param variables: a dict() of substitution values required by the
541 :param fip_name: the name of the floating IP to use for applying the
542 playbook (default - will take the first)
543 :return: the return value from ansible
545 return ansible_utils.apply_playbook(
546 pb_file_loc, [self.get_floating_ip(fip_name=fip_name).ip],
547 self.get_image_user(), self.keypair_settings.private_filepath,
548 variables, self._os_creds.proxy_settings)
550 def get_image_user(self):
552 Returns the instance sudo_user if it has been configured in the
553 instance_settings else it returns the image_settings.image_user value
555 if self.instance_settings.sudo_user:
556 return self.instance_settings.sudo_user
558 return self.image_settings.image_user
560 def vm_deleted(self, block=False, poll_interval=POLL_INTERVAL):
562 Returns true when the VM status returns the value of
563 expected_status_code or instance retrieval throws a NotFound exception.
564 :param block: When true, thread will block until active or timeout
565 value in seconds has been exceeded (False)
566 :param poll_interval: The polling interval in seconds
570 return self.__vm_status_check(
571 STATUS_DELETED, block,
572 self.instance_settings.vm_delete_timeout, poll_interval)
573 except NotFound as e:
575 "Instance not found when querying status for %s with message "
576 "%s", STATUS_DELETED, e)
579 def vm_active(self, block=False, poll_interval=POLL_INTERVAL):
581 Returns true when the VM status returns the value of the constant
583 :param block: When true, thread will block until active or timeout
584 value in seconds has been exceeded (False)
585 :param poll_interval: The polling interval in seconds
588 return self.__vm_status_check(STATUS_ACTIVE, block,
589 self.instance_settings.vm_boot_timeout,
592 def __vm_status_check(self, expected_status_code, block, timeout,
595 Returns true when the VM status returns the value of
597 :param expected_status_code: instance status evaluated with this
599 :param block: When true, thread will block until active or timeout
600 value in seconds has been exceeded (False)
601 :param timeout: The timeout value
602 :param poll_interval: The polling interval in seconds
605 # sleep and wait for VM status change
609 return self.__status(expected_status_code)
611 while timeout > time.time() - start:
612 status = self.__status(expected_status_code)
614 logger.info('VM is - ' + expected_status_code)
617 logger.debug('Retry querying VM status in ' + str(
618 poll_interval) + ' seconds')
619 time.sleep(poll_interval)
620 logger.debug('VM status query timeout in ' + str(
621 timeout - (time.time() - start)))
624 'Timeout checking for VM status for ' + expected_status_code)
627 def __status(self, expected_status_code):
629 Returns True when active else False
630 :param expected_status_code: instance status evaluated with this string
635 if expected_status_code == STATUS_DELETED:
640 status = nova_utils.get_server_status(self._nova, self.__vm)
642 logger.warning('Cannot find instance with id - ' + self.__vm.id)
645 if status == 'ERROR':
646 raise VmInstanceCreationError(
647 'Instance had an error during deployment')
649 'Instance status [%s] is - %s', self.instance_settings.name,
651 return status == expected_status_code
653 def vm_ssh_active(self, block=False, poll_interval=POLL_INTERVAL):
655 Returns true when the VM can be accessed via SSH
656 :param block: When true, thread will block until active or timeout
657 value in seconds has been exceeded (False)
658 :param poll_interval: The polling interval
661 # sleep and wait for VM status change
662 logger.info('Checking if VM is active')
664 timeout = self.instance_settings.ssh_connect_timeout
666 if self.vm_active(block=True):
670 start = time.time() - timeout
672 while timeout > time.time() - start:
673 status = self.__ssh_active()
675 logger.info('SSH is active for VM instance')
678 logger.debug('Retry SSH connection in ' + str(
679 poll_interval) + ' seconds')
680 time.sleep(poll_interval)
681 logger.debug('SSH connection timeout in ' + str(
682 timeout - (time.time() - start)))
684 logger.error('Timeout attempting to connect with VM via SSH')
687 def __ssh_active(self):
689 Returns True when can create a SSH session else False
692 if len(self.__floating_ip_dict) > 0:
693 ssh = self.ssh_client()
699 def get_floating_ip(self, fip_name=None):
701 Returns the floating IP object byt name if found, else the first known,
703 :param fip_name: the name of the floating IP to return
704 :return: the SSH client or None
707 if fip_name and self.__floating_ip_dict.get(fip_name):
708 return self.__floating_ip_dict.get(fip_name)
710 return self.__get_first_provisioning_floating_ip()
712 def ssh_client(self, fip_name=None):
714 Returns an SSH client using the name or the first known floating IP if
716 :param fip_name: the name of the floating IP to return
717 :return: the SSH client or None
719 fip = self.get_floating_ip(fip_name)
721 return ansible_utils.ssh_client(
722 self.__get_first_provisioning_floating_ip().ip,
723 self.get_image_user(),
724 self.keypair_settings.private_filepath,
725 proxy_settings=self._os_creds.proxy_settings)
728 'Cannot return an SSH client. No Floating IP configured')
730 def add_security_group(self, security_group):
732 Adds a security group to this VM. Call will block until VM is active.
733 :param security_group: the SNAPS SecurityGroup domain object
734 :return True if successful else False
736 self.vm_active(block=True)
738 if not security_group:
739 logger.warning('Security group object is None, cannot add')
743 nova_utils.add_security_group(self._nova, self.get_vm_inst(),
746 except NotFound as e:
747 logger.warning('Security group not added - ' + str(e))
750 def remove_security_group(self, security_group):
752 Removes a security group to this VM. Call will block until VM is active
753 :param security_group: the OpenStack security group object
754 :return True if successful else False
756 self.vm_active(block=True)
758 if not security_group:
759 logger.warning('Security group object is None, cannot remove')
763 nova_utils.remove_security_group(self._nova, self.get_vm_inst(),
766 except NotFound as e:
767 logger.warning('Security group not removed - ' + str(e))
771 class VmInstanceSettings:
773 Class responsible for holding configuration setting for a VM Instance
776 def __init__(self, **kwargs):
779 :param name: the name of the VM
780 :param flavor: the VM's flavor name
781 :param port_settings: the port configuration settings (required)
782 :param security_group_names: a set of names of the security groups to
784 :param floating_ip_settings: the floating IP configuration settings
785 :param sudo_user: the sudo user of the VM that will override the
786 instance_settings.image_user when trying to
788 :param vm_boot_timeout: the amount of time a thread will sleep waiting
789 for an instance to boot
790 :param vm_delete_timeout: the amount of time a thread will sleep
791 waiting for an instance to be deleted
792 :param ssh_connect_timeout: the amount of time a thread will sleep
793 waiting obtaining an SSH connection to a VM
794 :param availability_zone: the name of the compute server on which to
795 deploy the VM (optional)
796 :param volume_names: a list of the names of the volume to attach
798 :param userdata: the string contents of any optional cloud-init script
799 to execute after the VM has been activated.
800 This value may also contain a dict who's key value
801 must contain the key 'cloud-init_file' which denotes
802 the location of some file containing the cloud-init
805 self.name = kwargs.get('name')
806 self.flavor = kwargs.get('flavor')
807 self.sudo_user = kwargs.get('sudo_user')
808 self.userdata = kwargs.get('userdata')
810 self.port_settings = list()
811 port_settings = kwargs.get('ports')
812 if not port_settings:
813 port_settings = kwargs.get('port_settings')
815 for port_setting in port_settings:
816 if isinstance(port_setting, dict):
817 self.port_settings.append(PortSettings(**port_setting))
818 elif isinstance(port_setting, PortSettings):
819 self.port_settings.append(port_setting)
821 if kwargs.get('security_group_names'):
822 if isinstance(kwargs['security_group_names'], list):
823 self.security_group_names = kwargs['security_group_names']
824 elif isinstance(kwargs['security_group_names'], set):
825 self.security_group_names = kwargs['security_group_names']
826 elif isinstance(kwargs['security_group_names'], str):
827 self.security_group_names = [kwargs['security_group_names']]
829 raise VmInstanceSettingsError(
830 'Invalid data type for security_group_names attribute')
832 self.security_group_names = set()
834 self.floating_ip_settings = list()
835 floating_ip_settings = kwargs.get('floating_ips')
836 if not floating_ip_settings:
837 floating_ip_settings = kwargs.get('floating_ip_settings')
838 if floating_ip_settings:
839 for floating_ip_config in floating_ip_settings:
840 if isinstance(floating_ip_config, FloatingIpSettings):
841 self.floating_ip_settings.append(floating_ip_config)
843 self.floating_ip_settings.append(FloatingIpSettings(
844 **floating_ip_config['floating_ip']))
846 self.vm_boot_timeout = kwargs.get('vm_boot_timeout', 900)
847 self.vm_delete_timeout = kwargs.get('vm_delete_timeout', 300)
848 self.ssh_connect_timeout = kwargs.get('ssh_connect_timeout', 180)
849 self.availability_zone = kwargs.get('availability_zone')
850 self.volume_names = kwargs.get('volume_names')
852 if self.volume_names and not isinstance(self.volume_names, list):
853 raise VmInstanceSettingsError('volume_names must be a list')
855 if not self.name or not self.flavor:
856 raise VmInstanceSettingsError(
857 'Instance configuration requires the attributes: name, flavor')
859 if len(self.port_settings) == 0:
860 raise VmInstanceSettingsError(
861 'Instance configuration requires port settings (aka. NICS)')
864 class FloatingIpSettings:
866 Class responsible for holding configuration settings for a floating IP
869 def __init__(self, **kwargs):
872 :param name: the name of the floating IP
873 :param port_name: the name of the router to the external network
874 :param router_name: the name of the router to the external network
875 :param subnet_name: the name of the subnet on which to attach the
877 :param provisioning: when true, this floating IP can be used for
880 TODO - provisioning flag is a hack as I have only observed a single
881 Floating IPs that actually works on an instance. Multiple floating IPs
882 placed on different subnets from the same port are especially
883 troublesome as you cannot predict which one will actually connect.
884 For now, it is recommended not to setup multiple floating IPs on an
885 instance unless absolutely necessary.
887 self.name = kwargs.get('name')
888 self.port_name = kwargs.get('port_name')
889 self.port_id = kwargs.get('port_id')
890 self.router_name = kwargs.get('router_name')
891 self.subnet_name = kwargs.get('subnet_name')
892 if kwargs.get('provisioning') is not None:
893 self.provisioning = kwargs['provisioning']
895 self.provisioning = True
897 # if not self.name or not self.port_name or not self.router_name:
898 if not self.name or not self.router_name:
899 raise FloatingIpSettingsError(
900 'The attributes name, port_name and router_name are required')
902 if not self.port_name and not self.port_id:
903 raise FloatingIpSettingsError(
904 'The attributes port_name or port_id are required')
907 class VmInstanceSettingsError(Exception):
909 Exception to be thrown when an VM instance settings are incorrect
913 class FloatingIpSettingsError(Exception):
915 Exception to be thrown when an VM instance settings are incorrect
919 class VmInstanceCreationError(Exception):
921 Exception to be thrown when an VM instance cannot be created