def _update_physical_state(self, context, host, instance, state):
     instance_id = None
     if instance:
         instance_id = instance.id
     db.phy_host_update(context, host.id,
         {'instance_id': instance_id,
         'task_state' : state,
         })
    def spawn(self, context, instance, image_meta,
              network_info=None, block_device_info=None):
        LOG.debug("spawn:")
        LOG.debug("instance=%s", instance.__dict__)
        LOG.debug("image_meta=%s", image_meta)
        LOG.debug("network_info=%s", network_info)
        LOG.debug("block_device_info=%s", block_device_info)
        # TODO: handle block devices

        host = self._find_suitable_phy_host(context, instance)

        if not host:
            LOG.info("no suitable physical host found")
            raise NoSuitablePhyHost()

        db.phy_host_update(context, host['id'],
                           {'instance_id': instance['id'],
                            'task_state' : physical_states.BUILDING,
                            })

        nics_in_order = []
        pifs = db.phy_interface_get_all_by_phy_host_id(context, host['id'])
        for pif in pifs:
            nics_in_order.append(pif['address'])
            if pif.vif_uuid:
                db.phy_interface_set_vif_uuid(context, pif.id, None)
        nics_in_order.append(host['pxe_mac_address'])
        
        image_root = os.path.join(FLAGS.instances_path, instance['name'])
        tftp_root = FLAGS.physical_tftp_root

        os.mkdir(image_root)

        if FLAGS.physical_pxe_vlan_per_host:
            parent_interface = FLAGS.physical_pxe_parent_interface
            pxe_ip_id = db.phy_pxe_ip_associate(context, host.id)
            pxe_ip = db.phy_pxe_ip_get(context, pxe_ip_id)
            vlan_num = host.pxe_vlan_id
            server_address = pxe_ip.server_address
            client_address = pxe_ip.address
            tftp_root = os.path.join(tftp_root, str(instance['id']))

            pxe_interface = vlan.ensure_vlan(vlan_num, parent_interface)

            from nova.network import linux_net
            chain = 'phy-%s' % pxe_interface
            iptables = linux_net.iptables_manager
            iptables.ipv4['filter'].add_chain(chain)
            iptables.ipv4['filter'].add_rule('INPUT', '-i %s -j $%s' % (pxe_interface, chain))
            iptables.ipv4['filter'].add_rule(chain, '--proto udp --sport=68 --dport=67 -j ACCEPT')
            iptables.ipv4['filter'].add_rule(chain, '-s %s -j ACCEPT' % client_address)
            iptables.ipv4['filter'].add_rule(chain, '-j DROP')
            iptables.apply()

            #execute('ip', 'address',
            #        'add', server_address,
            #        'peer', client_address,
            #        'dev', pxe_interface,
            #        run_as_root=True)
            #execute('ip', 'link', 'set', pxe_interface, 'up', run_as_root=True)
            execute('ip', 'address',
                    'add', server_address + '/24',
                    'dev', pxe_interface,
                    run_as_root=True)
            execute('ip', 'route', 'add',
                    client_address, 'scope', 'host', 'dev', pxe_interface,
                    run_as_root=True)

            os.mkdir(tftp_root)
            shutil.copyfile(FLAGS.physical_pxelinux_path, os.path.join(tftp_root, 'pxelinux.0'))
            os.mkdir(os.path.join(tftp_root, 'pxelinux.cfg'))

            pxe.start_pxe_server(interface=pxe_interface,
                                 tftp_root=tftp_root,
                                 client_address=client_address,
                                 pid_path=_dnsmasq_pid_path(pxe_interface),
                                 lease_path=_dnsmasq_lease_path(pxe_interface))
        
        self.plug_vifs(instance, network_info)

        ifcfgs = []
        if_num = -1
        for (network,mapping) in network_info:
            LOG.debug("mapping['mac'] = %s", mapping['mac'])
            if_num += 1
            device = "eth%d" % if_num
            pif = db.phy_interface_get_by_vif_uuid(context, mapping['vif_uuid'])
            if not pif:
                LOG.warn("vif_uuid:%s dose not associated to pif, unexpectedly", mapping['vif_uuid'])
                continue
            ifcfg = _build_ifcfg_string_from_mapping(device, pif.address, mapping)
            if FLAGS.physical_use_unsafe_vlan and mapping['should_create_vlan'] and network.get('vlan'):
                ifcfg += "," + network['vlan']
            LOG.debug("ifcfg: %s", ifcfg)
            ifcfgs.append(ifcfg)

        self._firewall_driver.setup_basic_filtering(instance, network_info)
        self._firewall_driver.update_instance_filter(instance, network_info)

        ami_id = str(image_meta['id'])
        aki_id = str(instance['kernel_id'])
        ari_id = str(instance['ramdisk_id'])
        deploy_aki_id = FLAGS.physical_deploy_kernel
        deploy_ari_id = FLAGS.physical_deploy_ramdisk

        image_target = os.path.join(image_root, ami_id)
        kernel_target = os.path.join(tftp_root, aki_id)
        ramdisk_target = os.path.join(tftp_root, ari_id)
        deploy_kernel_target = os.path.join(tftp_root, deploy_aki_id)
        deploy_ramdisk_target = os.path.join(tftp_root, deploy_ari_id)

        LOG.debug("fetching image id=%s target=%s", ami_id, image_target)
        self._cache_image_x(context=context,
                            target=image_target,
                            image_id=ami_id,
                            user_id=instance['user_id'],
                            project_id=instance['project_id'])
        LOG.debug("injecting to image id=%s target=%s", ami_id, image_target)
        self._inject_to_image(image_target, instance, network_info, nics_in_order)

        LOG.debug("fetching kernel id=%s target=%s", aki_id, kernel_target)
        self._cache_image_x(context=context,
                          image_id=aki_id,
                          target=kernel_target,
                          user_id=instance['user_id'],
                          project_id=instance['project_id'])

        LOG.debug("fetching ramdisk id=%s target=%s", ari_id, ramdisk_target)
        self._cache_image_x(context=context,
                          image_id=ari_id,
                          target=ramdisk_target,
                          user_id=instance['user_id'],
                          project_id=instance['project_id'])

        LOG.debug("fetching deploy_kernel id=%s target=%s", aki_id, kernel_target)
        self._cache_image_x(context=context,
                          image_id=deploy_aki_id,
                          target=deploy_kernel_target,
                          user_id=instance['user_id'],
                          project_id=instance['project_id'])

        LOG.debug("fetching deploy_ramdisk id=%s target=%s", ari_id, ramdisk_target)
        self._cache_image_x(context=context,
                          image_id=deploy_ari_id,
                          target=deploy_ramdisk_target,
                          user_id=instance['user_id'],
                          project_id=instance['project_id'])

        LOG.debug("fetching images all done")

        pxe_config_path = os.path.join(tftp_root, 'pxelinux.cfg', "01-" + host.pxe_mac_address.replace(":", "-").lower())

        root_mb = instance['root_gb'] * 1024

        inst_type_id = instance['instance_type_id']
        inst_type = instance_types.get_instance_type(inst_type_id)
        swap_mb = inst_type['swap']
        if swap_mb < 1024:
            swap_mb = 1024

        deployment_key = _random_alnum(32)
        deployment_id = db.phy_deployment_create(context, deployment_key, image_target, pxe_config_path, root_mb, swap_mb)

        # 'default deploy' will be replaced to 'default boot' by phy_deploy_work
        pxeconf = "default deploy\n"
        pxeconf += "\n"

        pxeconf += "label deploy\n"
        pxeconf += "kernel %s\n" % deploy_aki_id
        pxeconf += "append"
        pxeconf += " initrd=%s" % deploy_ari_id
        pxeconf += " selinux=0"
        pxeconf += " disk=cciss/c0d0,sda,hda"
        pxeconf += " iscsi_target_iqn=iqn-%s" % str(instance['uuid'])
        pxeconf += " deployment_id=%s" % deployment_id
        pxeconf += " deployment_key=%s" % deployment_key
        pxeconf += "\n"
        pxeconf += "ipappend 3\n"
        pxeconf += "\n"

        pxeconf += "label boot\n"
        pxeconf += "kernel %s\n" % aki_id
        pxeconf += "append"
        pxeconf += " initrd=%s" % ari_id
        # ${ROOT} will be replaced to UUID=... by phy_deploy_work
        pxeconf += " root=${ROOT} ro"
        pxeconf += "\n"
        pxeconf += "\n"

        f = open(pxe_config_path, 'w')
        f.write(pxeconf)
        f.close()

        if not host.ipmi_address:
            LOG.warn("Since ipmi_address is empty, power_off_on is not performed")

        LOG.debug("power on")
        pm = _get_ipmi(host.ipmi_address, host.ipmi_user, host.ipmi_password)
        state = pm.power_off()
        self._update_physical_state(context, host, instance, state)
        state = pm.power_on()
        self._update_physical_state(context, host, instance, state)

        if FLAGS.physical_console:
            (out,err) = execute(FLAGS.physical_console,
                                '--ipmi_address=%s' % host.ipmi_address,
                                '--ipmi_user=%s' % host.ipmi_user,
                                '--ipmi_password=%s' % host.ipmi_password,
                                '--terminal_port=%s' % host.terminal_port,
                                '--pidfile=%s' % _console_pidfile(host.id),
                                run_as_root=True)

            LOG.debug("physical_console: out=%s", out)
            LOG.debug("physical_console: err=%s", err)