149 # and what is not supported. A HYPERVISOR_VERSION is defined here for |
149 # and what is not supported. A HYPERVISOR_VERSION is defined here for |
150 # Nova's use but it generally should not be changed unless there is a |
150 # Nova's use but it generally should not be changed unless there is a |
151 # incompatible change such as concerning kernel zone live migration. |
151 # incompatible change such as concerning kernel zone live migration. |
152 HYPERVISOR_VERSION = '5.11' |
152 HYPERVISOR_VERSION = '5.11' |
153 |
153 |
|
154 shared_storage = ['iscsi', 'fibre_channel'] |
|
155 |
154 |
156 |
155 def lookup_resource(zone, resource): |
157 def lookup_resource(zone, resource): |
156 """Lookup specified resource from specified Solaris Zone.""" |
158 """Lookup specified resource from specified Solaris Zone.""" |
157 try: |
159 try: |
158 val = zone.getResources(zonemgr.Resource(resource)) |
160 val = zone.getResources(zonemgr.Resource(resource)) |
788 """Return the UUIDS of all the instances known to the virtualization |
790 """Return the UUIDS of all the instances known to the virtualization |
789 layer, as a list. |
791 layer, as a list. |
790 """ |
792 """ |
791 raise NotImplementedError() |
793 raise NotImplementedError() |
792 |
794 |
|
795 def _rebuild_block_devices(self, context, instance, bdms, recreate): |
|
796 root_ci = None |
|
797 rootmp = instance['root_device_name'] |
|
798 for entry in bdms: |
|
799 if entry['connection_info'] is None: |
|
800 continue |
|
801 |
|
802 if entry['device_name'] == rootmp: |
|
803 root_ci = jsonutils.loads(entry['connection_info']) |
|
804 continue |
|
805 |
|
806 if not recreate: |
|
807 self._volume_api.detach(context, |
|
808 entry['connection_info']['serial']) |
|
809 |
|
810 if root_ci is None: |
|
811 msg = (_("Unable to find the root device for instance %s") |
|
812 % instance.display_name) |
|
813 raise exception.NovaException(msg) |
|
814 |
|
815 return root_ci |
|
816 |
793 def rebuild(self, context, instance, image_meta, injected_files, |
817 def rebuild(self, context, instance, image_meta, injected_files, |
794 admin_password, bdms, detach_block_devices, |
818 admin_password, bdms, detach_block_devices, |
795 attach_block_devices, network_info=None, |
819 attach_block_devices, network_info=None, |
796 recreate=False, block_device_info=None, |
820 recreate=False, block_device_info=None, |
797 preserve_ephemeral=False): |
821 preserve_ephemeral=False): |
828 :param block_device_info: Information about block devices to be |
852 :param block_device_info: Information about block devices to be |
829 attached to the instance. |
853 attached to the instance. |
830 :param preserve_ephemeral: True if the default ephemeral storage |
854 :param preserve_ephemeral: True if the default ephemeral storage |
831 partition must be preserved on rebuild |
855 partition must be preserved on rebuild |
832 """ |
856 """ |
833 raise NotImplementedError() |
857 # rebuild is not supported yet. |
|
858 if not recreate: |
|
859 raise NotImplementedError() |
|
860 |
|
861 extra_specs = self._get_extra_specs(instance) |
|
862 brand = extra_specs.get('zonecfg:brand', ZONE_BRAND_SOLARIS) |
|
863 if recreate and brand == ZONE_BRAND_SOLARIS: |
|
864 msg = (_("'%s' branded zones do not currently support " |
|
865 "evacuation.") % brand) |
|
866 raise exception.NovaException(msg) |
|
867 |
|
868 instance.task_state = task_states.REBUILD_BLOCK_DEVICE_MAPPING |
|
869 instance.save(expected_task_state=[task_states.REBUILDING]) |
|
870 |
|
871 root_ci = self._rebuild_block_devices(context, instance, bdms, |
|
872 recreate) |
|
873 |
|
874 driver_type = root_ci['driver_volume_type'] |
|
875 # If image_meta is provided then the --on-shared-storage option |
|
876 # was not used. |
|
877 if image_meta: |
|
878 # Check to make sure that the root device is actually local. |
|
879 # If not then raise an exception |
|
880 if driver_type in shared_storage: |
|
881 msg = (_("Root device is on shared storage for instance '%s'") |
|
882 % instance['name']) |
|
883 raise exception.NovaException(msg) |
|
884 |
|
885 if recreate: |
|
886 msg = (_("Evacuate a single host node is not supported")) |
|
887 raise exception.NovaException(msg) |
|
888 else: |
|
889 # So the root device is not expected to be local so we can move |
|
890 # forward with building the zone. |
|
891 if driver_type not in shared_storage: |
|
892 msg = (_("Root device is not on shared storage for instance" |
|
893 "'%s'") % instance['name']) |
|
894 raise exception.NovaException(msg) |
|
895 |
|
896 instance.task_state = task_states.REBUILD_SPAWNING |
|
897 instance.save( |
|
898 expected_task_state=[task_states.REBUILD_BLOCK_DEVICE_MAPPING]) |
|
899 inst_type = flavor_obj.Flavor.get_by_id( |
|
900 nova_context.get_admin_context(read_deleted='yes'), |
|
901 instance['instance_type_id']) |
|
902 extra_specs = inst_type['extra_specs'].copy() |
|
903 |
|
904 self._create_config(context, instance, network_info, |
|
905 root_ci, extra_specs, None) |
|
906 |
|
907 name = instance['name'] |
|
908 zone = self._get_zone_by_name(name) |
|
909 if zone is None: |
|
910 raise exception.InstanceNotFound(instance_id=name) |
|
911 |
|
912 zone.attach(['-x', 'initialize-hostdata']) |
|
913 |
|
914 instance_uuid = instance.uuid |
|
915 rootmp = instance['root_device_name'] |
|
916 for entry in bdms: |
|
917 if (entry['connection_info'] is None or |
|
918 rootmp == entry['device_name']): |
|
919 continue |
|
920 |
|
921 connection_info = jsonutils.loads(entry['connection_info']) |
|
922 mount = entry['device_name'] |
|
923 self.attach_volume(context, connection_info, instance, mount) |
|
924 |
|
925 self._power_on(instance) |
834 |
926 |
835 def _get_extra_specs(self, instance): |
927 def _get_extra_specs(self, instance): |
836 """Retrieve extra_specs of an instance.""" |
928 """Retrieve extra_specs of an instance.""" |
837 flavor = flavor_obj.Flavor.get_by_id( |
929 flavor = flavor_obj.Flavor.get_by_id( |
838 nova_context.get_admin_context(read_deleted='yes'), |
930 nova_context.get_admin_context(read_deleted='yes'), |
1313 if template is None: |
1405 if template is None: |
1314 msg = (_("Invalid brand '%s' specified for instance '%s'" |
1406 msg = (_("Invalid brand '%s' specified for instance '%s'" |
1315 % (brand, name))) |
1407 % (brand, name))) |
1316 raise exception.NovaException(msg) |
1408 raise exception.NovaException(msg) |
1317 |
1409 |
|
1410 # XXX - Adding the REBUILDING task state, but we may want to |
|
1411 # check the sysconfig if the host is completely rebuilding. |
1318 tstate = instance['task_state'] |
1412 tstate = instance['task_state'] |
1319 if tstate not in [task_states.RESIZE_FINISH, |
1413 if tstate not in [task_states.RESIZE_FINISH, |
1320 task_states.RESIZE_REVERTING, |
1414 task_states.RESIZE_REVERTING, |
1321 task_states.RESIZE_MIGRATING]: |
1415 task_states.RESIZE_MIGRATING, |
|
1416 task_states.REBUILD_SPAWNING]: |
1322 sc_profile = extra_specs.get('install:sc_profile') |
1417 sc_profile = extra_specs.get('install:sc_profile') |
1323 if sc_profile is not None: |
1418 if sc_profile is not None: |
1324 if os.path.isfile(sc_profile): |
1419 if os.path.isfile(sc_profile): |
1325 shutil.copy(sc_profile, sc_dir) |
1420 shutil.copy(sc_profile, sc_dir) |
1326 elif os.path.isdir(sc_profile): |
1421 elif os.path.isdir(sc_profile): |
3669 |
3764 |
3670 .. note:: |
3765 .. note:: |
3671 Used in rebuild for HA implementation and required for validation |
3766 Used in rebuild for HA implementation and required for validation |
3672 of access to instance shared disk files |
3767 of access to instance shared disk files |
3673 """ |
3768 """ |
3674 return False |
3769 bdmobj = objects.BlockDeviceMappingList |
|
3770 mappings = bdmobj.get_by_instance_uuid( |
|
3771 nova_context.get_admin_context(), |
|
3772 instance['uuid']) |
|
3773 |
|
3774 rootmp = instance['root_device_name'] |
|
3775 for entry in mappings: |
|
3776 if entry['connection_info'] is None: |
|
3777 continue |
|
3778 |
|
3779 if entry['device_name'] == rootmp: |
|
3780 root_ci = jsonutils.loads(entry['connection_info']) |
|
3781 break |
|
3782 |
|
3783 if root_ci is None: |
|
3784 msg = (_("Unable to find the root device for instance %s", |
|
3785 instance.display_name)) |
|
3786 raise exception.NovaException(msg) |
|
3787 |
|
3788 driver_type = root_ci['driver_volume_type'] |
|
3789 if driver_type in shared_storage: |
|
3790 return True |
|
3791 else: |
|
3792 return False |
3675 |
3793 |
3676 def register_event_listener(self, callback): |
3794 def register_event_listener(self, callback): |
3677 """Register a callback to receive events. |
3795 """Register a callback to receive events. |
3678 |
3796 |
3679 Register a callback to receive asynchronous event |
3797 Register a callback to receive asynchronous event |