def _spawn(self, context, instance, image_meta, step, create_disks_step,
               first_boot, injected_files=None, admin_password=None,
               network_info=None, block_device_info=None,
               name_label=None, rescue=False, power_on=True, resize=True,
               completed_callback=None):
        if name_label is None:
            name_label = instance['name']

        self._ensure_instance_name_unique(name_label)
        self._ensure_enough_free_mem(instance)

        def attach_disks(undo_mgr, vm_ref, vdis, disk_image_type):
            if image_meta.properties.get('hw_ipxe_boot', False):
                if 'iso' in vdis:
                    vm_utils.handle_ipxe_iso(
                        self._session, instance, vdis['iso'], network_info)
                else:
                    LOG.warning(_LW('ipxe_boot is True but no ISO image '
                                    'found'), instance=instance)

            if resize:
                self._resize_up_vdis(instance, vdis)

            self._attach_disks(instance, image_meta, vm_ref, name_label, vdis,
                               disk_image_type, network_info, rescue,
                               admin_password, injected_files)
            if not first_boot:
                self._attach_mapped_block_devices(instance,
                                                  block_device_info)

        def attach_pci_devices(undo_mgr, vm_ref):
            dev_to_passthrough = ""
            devices = pci_manager.get_instance_pci_devs(instance)
            for d in devices:
                pci_address = d["address"]
                if pci_address.count(":") == 1:
                    pci_address = "0000:" + pci_address
                dev_to_passthrough += ",0/" + pci_address

            # Remove the first comma if string is not empty.
            # Note(guillaume-thouvenin): If dev_to_passthrough is empty, we
            #                            don't need to update other_config.
            if dev_to_passthrough:
                vm_utils.set_other_config_pci(self._session,
                                              vm_ref,
                                              dev_to_passthrough[1:])

        @step
        def determine_disk_image_type_step(undo_mgr):
            return vm_utils.determine_disk_image_type(image_meta)

        @step
        def create_kernel_ramdisk_step(undo_mgr):
            kernel_file, ramdisk_file = vm_utils.create_kernel_and_ramdisk(
                    context, self._session, instance, name_label)

            def undo_create_kernel_ramdisk():
                vm_utils.destroy_kernel_ramdisk(self._session, instance,
                        kernel_file, ramdisk_file)

            undo_mgr.undo_with(undo_create_kernel_ramdisk)
            return kernel_file, ramdisk_file

        @step
        def create_vm_record_step(undo_mgr, disk_image_type,
                                  kernel_file, ramdisk_file):
            vm_ref = self._create_vm_record(context, instance, name_label,
                                            disk_image_type, kernel_file,
                                            ramdisk_file, image_meta, rescue)

            def undo_create_vm():
                self._destroy(instance, vm_ref, network_info=network_info)

            undo_mgr.undo_with(undo_create_vm)
            return vm_ref

        @step
        def attach_devices_step(undo_mgr, vm_ref, vdis, disk_image_type):
            attach_disks(undo_mgr, vm_ref, vdis, disk_image_type)
            attach_pci_devices(undo_mgr, vm_ref)

        if rescue:
            # NOTE(johannes): Attach disks from original VM to rescue VM now,
            # before booting the VM, since we can't hotplug block devices
            # on non-PV guests
            @step
            def attach_orig_disks_step(undo_mgr, vm_ref):
                vbd_refs = self._attach_orig_disks(instance, vm_ref)

                def undo_attach_orig_disks():
                    # Destroy the VBDs in preparation to re-attach the VDIs
                    # to its original VM.  (does not delete VDI)
                    for vbd_ref in vbd_refs:
                        vm_utils.destroy_vbd(self._session, vbd_ref)

                undo_mgr.undo_with(undo_attach_orig_disks)

        @step
        def inject_instance_data_step(undo_mgr, vm_ref, vdis):
            self._inject_instance_metadata(instance, vm_ref)
            self._inject_auto_disk_config(instance, vm_ref)
            # NOTE: We add the hostname here so windows PV tools
            # can pick it up during booting
            if first_boot:
                self._inject_hostname(instance, vm_ref, rescue)
            self._file_inject_vm_settings(instance, vm_ref, vdis, network_info)
            self.inject_network_info(instance, network_info, vm_ref)

        @step
        def setup_network_step(undo_mgr, vm_ref):
            self._create_vifs(instance, vm_ref, network_info)
            self._prepare_instance_filter(instance, network_info)

        @step
        def start_paused_step(undo_mgr, vm_ref):
            if power_on:
                self._start(instance, vm_ref, start_pause=True)

        @step
        def boot_and_configure_instance_step(undo_mgr, vm_ref):
            self._unpause_and_wait(vm_ref, instance, power_on)
            if first_boot:
                self._configure_new_instance_with_agent(instance, vm_ref,
                        injected_files, admin_password)
                self._remove_hostname(instance, vm_ref)

        @step
        def apply_security_group_filters_step(undo_mgr):
            self.firewall_driver.apply_instance_filter(instance, network_info)

        undo_mgr = utils.UndoManager()
        try:
            # NOTE(sirp): The create_disks() step will potentially take a
            # *very* long time to complete since it has to fetch the image
            # over the network and images can be several gigs in size. To
            # avoid progress remaining at 0% for too long, make sure the
            # first step is something that completes rather quickly.
            disk_image_type = determine_disk_image_type_step(undo_mgr)

            vdis = create_disks_step(undo_mgr, disk_image_type, image_meta,
                                     name_label)
            kernel_file, ramdisk_file = create_kernel_ramdisk_step(undo_mgr)

            vm_ref = create_vm_record_step(undo_mgr, disk_image_type,
                    kernel_file, ramdisk_file)
            attach_devices_step(undo_mgr, vm_ref, vdis, disk_image_type)

            inject_instance_data_step(undo_mgr, vm_ref, vdis)

            # if use neutron, prepare waiting event from neutron
            # first_boot is True in new booted instance
            # first_boot is False in migration and we don't waiting
            # for neutron event regardless of whether or not it is
            # migrated to another host, if unplug VIFs locally, the
            # port status may not changed in neutron side and we
            # cannot get the vif plug event from neturon
            timeout = CONF.vif_plugging_timeout
            events = self._get_neutron_events(network_info,
                                              power_on, first_boot)
            try:
                with self._virtapi.wait_for_instance_event(
                    instance, events, deadline=timeout,
                    error_callback=self._neutron_failed_callback):
                    LOG.debug("wait for instance event:%s", events)
                    setup_network_step(undo_mgr, vm_ref)
                    if rescue:
                        attach_orig_disks_step(undo_mgr, vm_ref)
                    start_paused_step(undo_mgr, vm_ref)
            except eventlet.timeout.Timeout:
                self._handle_neutron_event_timeout(instance, undo_mgr)

            apply_security_group_filters_step(undo_mgr)
            boot_and_configure_instance_step(undo_mgr, vm_ref)
            if completed_callback:
                completed_callback()
        except Exception:
            msg = _("Failed to spawn, rolling back")
            undo_mgr.rollback_and_reraise(msg=msg, instance=instance)
dataset/ETHPy150Open openstack/nova/nova/virt/xenapi/vmops.py/VMOps._spawn/original