nova novnc支持https

配置步骤:
1.生成自签名认证文件和密钥:

2.修改nova.conf(novnc proxy节点)

注意权限为novnc启动所用的账户,重启novnc服务
3.修改nova.conf(计算节点)

重启nova-compute服务。

还需要考虑加上CA认证,否则浏览器会提示”此网站的安全证书有问题。”

Linux云主机初始登录密码修改方案

原文地址:http://aspirer2004.blog.163.com/blog/static/1067647201452624733337/

目前我们的虚拟机创建后的密码是在制作镜像时指定的,所以存在一个安全风险,一旦一台云主机的密码被破解,所有云主机都面临安全风险,不过由于我们已经禁用了ssh方式密码登录,大部分虚拟机都位于内网,这种风险目前看来比较小,但为了更加安全,以及满足公有云用户潜在的需求,所以后续可能需要支持用户自定义登录密码,或者修改初始密码为随机值,为此我这两天分析了一下相关实现方案,下面是一些总结。
类似风险还有VNC登录没有加密,用户只要获取经过认证的VNC窗口链接,即可使用用户名密码登录虚拟机,较好的方案是对VNC本身加密,首先要通过VNC的认证之后,才能接触到虚拟机console,这个问题已经有初步方案,还没安排实现。
Windows虚拟机的初始密码修改暂时没有分析,不过应该有如下几种:
1)cloudbase-init支持,类似下面的cloudinit方案 (推荐方案)
2)镜像制作的时候指定下次登录时密码过期,强制用户修改
3)使用agent修改
下面的方案在debian7上验证通过,并且仅可以在虚拟机创建前修改,创建后无法修改。
方案1:
使用类似文件注入的adminPass注入,不需要在虚拟机里面安装agent或cloudinit,
需要注意的事项:
1)cloudinit配置文件不能lock_passwd,也即配置为false,disable_root:false,或者不安装cloudinit
2)修改nova.conf,libvirt_inject_password = True
使用方法:创建虚拟机时在api传入adminPass参数,如不传则随机生成,并在响应结果中返回,但不会保存在nova数据库,用户必须牢记。
 
方案2:
创建虚拟机的api中传入user-data参数,配合cloudinit修改虚拟机密码:
虚拟机里面cloudinit的/etc/cloud/cloud.cfg配置文件中要有如下内容:
cloud_config_modules:
– set-passwords
可以修改默认用户,根据/etc/cloud/cloud.cfg配置文件中的
users:
– default
default_user:
name:root
来确定默认用户是那个。
user-data内容:
注意#cloud-config是内容格式的标识,不是注释,不能删除
#cloud-config
password: mysecret
chpasswd: { expire: False }
ssh_pwauth: True
最后一行可删除,禁用ssh密码登陆。
或者批量修改用户密码:
#cloud-config
chpasswd:
list: |
root:xxxx
debian:yyyy
expire: False
前提是要修改用户必须存在。
#cloud-config
chpasswd:
list: |
user1:password1
user2:RANDOM
expire: True
ssh_pwauth: [ True, False, “” or “unchanged” ]
其中RANDOM表示随机生成密码,expire表示是否在首次登陆的时候过期,如果为True,则用户首次登陆的时候必须修改密码。
ssh_pwauth默认值是不修改ssh密码认证方式,也即保持镜像制作时的配置。
如果ssh_pwauth设置为False,则密码认证方式只能通过VNC登录,不能ssh。

使用方法:nova boot 加上–user-data userdata.yaml参数,userdata.yaml内容见上面的#cloud-config

如何在nova中实现一个类似cinder的volume插件

原文地址:http://aspirer2004.blog.163.com/blog/static/1067647201422841039140/

github地址:https://github.com/aspirer/docfiles/raw/master/%E5%A6%82%E4%BD%95%E5%9C%A8nova%E4%B8%AD%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AA%E7%B1%BB%E4%BC%BCcinder%E7%9A%84volume%E6%8F%92%E4%BB%B6.docx

OneDrive(SkyDrive)地址:http://1drv.ms/1jBTNqK

nova 兼容Netease Block Service插件实现

1.      现状说明

本文基于havana版本nova来进行代码分析和原型实现。

实现一套新的volume插件的原因是,nbs不提供兼容cinder的api,无法使用现有的cinder插件,并且libvirt volume driver也没有nbs的实现,需要重新编写代码来完成这部分工作。

已有的实现是比较不好的一种方式,也即通过配置参数在api层区分是nbs 的volume还是cinder的volume,如果是nbs的就走新增加的挂卷、卸卷等流程(nbs支持扩容卷、修改卷QoS功能),这样就要维护很多冗余代码,包括从compute/api->compute/rpc_api->compute/manager->libvirt driver一整条代码链都要自己实现,并且绝大部分代码都是直接拷贝的cinder的实现流程,维护起来也很困难,一旦要进行大版本升级就带来很大的工作量,比如nova从F版本升级H版本的时候就花费了很长时间进行代码移植和测试工作。此外还有很多设计到卷的代码都要考虑兼容性问题,很多周边流程需要处理,导致很多与volume相关的功能在没有修改前都没办法使用。到目前为止还有很多功能都没能提供,比如unshelve、在线迁移、从volume启动虚拟机等等,我们仅仅实现了已有的基本功能(创建、删除、开机、关机、resize、cold migration等)。

2.      改进目标

基于上述原因,以及更重要的一点,为后续新功能开发做准备,我们想要实现一套新的的流程,目标是最大化的复用nova已有的代码,来完成挂卷、卸卷以及更多的涉及到卷操作的各种虚拟机生命周期管理功能。

也即达到如下目标:

  • 最大化的与nova当前的cinder流程保持兼容,可以不经改动支持现有的各种涉及到volume的操作
  • 尽量不增加新的配置项(多使用已有的配置项,但配置项的功能有少许差异),减少SA的运维工作
  • 减少私有代码量,尽量重用nova中已有实现,以减少代码维护工作量
  • 为后续涉及到volume的新功能开发做准备,比如从volume启动虚拟机,在线迁移虚拟机等功能
  • 使用更多的nova流程也可以利用社区的力量来帮我们完成一定的开发测试工作,我们也可以把自己的代码贡献到社区

 

3.      当前实现

直接拿代码来说明,这里是F版本移植H版本首次提交gerrit记录:https://scm.service.163.org/#/c/2049/18,下面截取部分代码段进行说明:

nova/api/openstack/compute/contrib/volumes.py:

@wsgi.serializers(xml=VolumeAttachmentTemplate)

def create(self, req, server_id, body):

“””Attach a volume to an instance.”””

# Go to our owned process if we are attaching a nbs volume

if CONF.ebs_backend == ‘nbs’:

return self._attach_nbs_volume(req, server_id, body)

 

nova/compute/api.py:

@check_instance_lock

@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.PAUSED,

vm_states.SUSPENDED, vm_states.STOPPED,

vm_states.RESIZED, vm_states.SOFT_DELETED],

task_state=None)

def attach_nbs_volume(self, context, instance, volume_id):

“””Attach an existing volume to an existing instance.”””

# NOTE(vish): This is done on the compute host because we want

#             to avoid a race where two devices are requested at

#             the same time. When db access is removed from

#             compute, the bdm will be created here and we will

#             have to make sure that they are assigned atomically.

 

# Raise exception if the instance is forbidden to attach volume.

allow_attach = self.check_allow_attach(context, instance)

if not allow_attach:

raise exception.NbsAttachForbidden()

 

# Check volume exists and is available to attach

# FIXME(wangpan): we just deal with single attachment status now

try:

volume = self.nbs_api.get(context, volume_id)[‘volumes’][0]

except (IndexError, KeyError, TypeError):

raise exception.VolumeNotFound(volume_id=volume_id)

 

nova/compute/manager.py:

@reverts_task_state

@wrap_instance_fault

def attach_nbs_volume(self, context, volume_id, device, instance):

“””Attach a nbs volume to an instance.”””

# TODO(wangpan): if this host is forbidden to attach nbs volume,

#                an exception needs to be raised.

try:

return self._attach_nbs_volume(context, volume_id,

device, instance)

except Exception:

with excutils.save_and_reraise_exception():

capi = self.conductor_api

capi.block_device_mapping_destroy_by_instance_and_volume(

context, instance, volume_id)

 

nova/virt/libvirt/driver.py:

def attach_nbs_volume(self, instance_name, device, host_dev,

qos_info, volume_id):

“””

Attach a nbs volume to instance, and check the device or slot is

in-use, return retry if in-use, if need retry, the used device is

returned, too.

“””

target_dev = device[‘mountpoint’].rpartition(“/”)[2]

 

conf = vconfig.LibvirtConfigGuestDisk()

conf.source_type = “block”

conf.driver_name = libvirt_utils.pick_disk_driver_name(

self.get_hypervisor_version(), is_block_dev=True)

conf.driver_format = “raw”

 

nova/compute/manager.py:

def _finish_resize():

……

nbs = (CONF.ebs_backend == ‘nbs’)

block_device_info = self._get_instance_volume_block_device_info(

context, instance, refresh_conn_info=True, is_nbs=nbs)

 

# re-attach nbs volumes if needed.

if nbs:

bdms = block_device_info.get(‘block_device_mapping’, [])

else:

bdms = []

same_host = (migration[‘source_compute’] == migration[‘dest_compute’])

# call nbs to re-attach volumes to this host if it is not resize to

# same host.

if nbs and bdms and not same_host:

host_ip = utils.get_host_ip_by_ifname(CONF.host_ip_ifname)

for bdm in bdms:

 

4.      改进实现

还是直接拿代码来说明,这里的提交是原型试验代码,有很多细节问题没有处理,但已经可以正常工作:https://scm.service.163.org/#/c/3090/

这次的实现是增加了类似cinder的插件,主要增加了nova/volume/nbs.py模块,它的功能是模仿同一目录下的cinder.py来实现的,这样nova的其他代码只要把默认的volume api从cinder改为nbs,就可以直接调用,它主要调用了nova/volume/nbs_client.py,这个文件是之前已经实现了的,主要用来调用nbs的api,跟nbs服务打交道,实现查询卷信息、挂载卷到宿主机、从宿主机上卸载卷等各种需要nbs完成的操作;另外还在nova/virt/libvirt/volume.py模块里面增加了LibvirtNBSVolumeDriver,这个类主要是为libvirt生成挂盘所需要的xml文件,由于实际底层挂卷到宿主机是nbs的agent来负责的,所以这部分功能也不用加到这里了(其他volume服务有些是需要的)。

简单来说就是主要增加nbs交互的前端模块(与nbs api交互)和半个后端模块(与libvirt交互,缺少了nbs自己维护的agent那部分功能)。

nova/volume/__init__.py:

_volume_opts = [

oslo.config.cfg.StrOpt(‘ebs_backend’,

default=’cinder’,

help=’The backend type of ebs service, ‘

‘should be nbs or cinder’),

oslo.config.cfg.StrOpt(‘volume_api_class’,

default=’nova.volume.cinder.API’,

help=’The full class name of the ‘

‘volume API class to use’),

]

 

“””

Handles all requests relating to volumes + nbs.

“””

 

import datetime

 

from nova.db import base

from nova import exception

from nova.openstack.common.gettextutils import _

from nova.openstack.common import jsonutils

from nova.openstack.common import log as logging

from nova.volume import nbs_client

 

 

LOG = logging.getLogger(__name__)

 

 

NBS_CLIENT = None

 

 

def nbsclient():

global NBS_CLIENT

if NBS_CLIENT is None:

NBS_CLIENT = nbs_client.API()

 

return NBS_CLIENT

 

 

def _untranslate_volume_summary_view(context, vol):

“””Maps keys for volumes summary view.”””

d = {}

d[‘id’] = vol[‘volumeId’]

d[‘status’] = vol[‘status’]

d[‘size’] = vol[‘size’]

d[‘availability_zone’] = vol[‘availabilityZone’]

created_at = long(vol[‘createTime’]) / 1000

created_at = datetime.datetime.utcfromtimestamp(created_at)

created_at = created_at.strftime(“%Y-%m-%d %H:%M:%S”)

d[‘created_at’] = created_at

 

d[‘attach_time’] = “”

d[‘mountpoint’] = “”

 

if vol[‘attachments’]:

att = vol[‘attachments’][0]

d[‘attach_status’] = att[‘status’]

d[‘instance_uuid’] = att[‘instanceId’]

d[‘mountpoint’] = att[‘device’]

d[‘attach_time’] = att[‘attachTime’]

else:

d[‘attach_status’] = ‘detached’

 

d[‘display_name’] = vol[‘volumeName’]

d[‘display_description’] = vol[‘volumeName’]

 

# FIXME(wangpan): all nbs volumes are ‘share’ type, so we fix here to 0

d[‘volume_type_id’] = 0

d[‘snapshot_id’] = vol[‘snapshotId’]

 

# NOTE(wangpan): nbs volumes don’t have metadata attribute

d[‘volume_metadata’] = {}

# NOTE(wangpan): nbs volumes don’t have image metadata attribute now

 

return d

 

 

class API(base.Base):

“””API for interacting with the volume manager.”””

 

def get(self, context, volume_id):

item = nbsclient().get(context, volume_id)[‘volumes’][0]

return _untranslate_volume_summary_view(context, item)

 

def get_all(self, context, search_opts={}):

items = nbsclient().get(context)[‘volumes’]

rval = []

 

for item in items:

rval.append(_untranslate_volume_summary_view(context, item))

 

return rval

 

def check_attached(self, context, volume):

“””Raise exception if volume not in use.”””

if volume[‘status’] != “in-use”:

msg = _(“status must be ‘in-use'”)

raise exception.InvalidVolume(reason=msg)

 

def check_attach(self, context, volume, instance=None):

# TODO(vish): abstract status checking?

if volume[‘status’] != “available”:

msg = _(“status must be ‘available'”)

raise exception.InvalidVolume(reason=msg)

if volume[‘attach_status’] in (“attached”, “attachedInVM”):

msg = _(“already attached”)

raise exception.InvalidVolume(reason=msg)

 

def check_detach(self, context, volume):

# TODO(vish): abstract status checking?

if volume[‘status’] == “available”:

msg = _(“already detached”)

raise exception.InvalidVolume(reason=msg)

if volume[‘attach_status’] not in (“attached”, “attachedInVM”):

msg = _(“volume not attached”)

raise exception.InvalidVolume(reason=msg)

 

def reserve_volume(self, context, volume_id):

“””We do not need to reserve nbs volume now.”””

pass

 

def unreserve_volume(self, context, volume_id):

“””We do not need to unreserve nbs volume now.”””

pass

 

def begin_detaching(self, context, volume_id):

“””We do not need to notify nbs begin detaching volume now.”””

pass

 

def roll_detaching(self, context, volume_id):

“””We do not need to roll detaching nbs volume now.”””

pass

 

def attach(self, context, volume_id, instance_uuid, mountpoint):

“””We do not need to change volume state now.

 

We implement this operation in volume driver.

“””

pass

 

def post_attach(self, context, volume_id, instance_uuid,

mountpoint, host_ip):

“””Tell NBS manager attachment success.”””

device = jsonutils.loads(mountpoint)

return nbsclient().notify_nbs_libvirt_result(context, volume_id,

‘attach’, True, device=device[‘real_path’],

host_ip=host_ip, instance_uuid=instance_uuid)

 

def detach(self, context, volume_id):

“””We do not need to change volume state now.

 

We implement this operation in volume driver.

“””

pass

 

def initialize_connection(self, context, volume_id, connector):

“””We do attachment of nbs volume to host in the method.”””

instance_uuid = connector[‘instance_uuid’]

host_ip = connector[‘ip’]

device = jsonutils.loads(connector[‘device’])

real_path = device[‘real_path’]

 

result = nbsclient().attach(context, volume_id, instance_uuid,

host_ip, real_path)

if result is None:

raise exception.NbsException()

 

# check volume status, wait for nbs attaching finish

succ = nbsclient().wait_for_attached(context, volume_id,

instance_uuid)

if not succ:

raise exception.NbsTimeout()

 

# get host dev path and QoS params from nbs

return nbsclient().get_host_dev_and_qos_info(

context, volume_id, host_ip)

 

def terminate_connection(self, context, volume_id, connector):

“””We do detachment of nbs volume from host in the method.”””

host_ip = connector[‘ip’]

return nbsclient().detach(context, volume_id, host_ip)

 

def migrate_volume_completion(self, context, old_volume_id, new_volume_id,

error=False):

raise NotImplementedError()

 

def create(self, context, size, name, description, snapshot=None,

image_id=None, volume_type=None, metadata=None,

availability_zone=None):

“””We do not support create nbs volume now.”””

raise NotImplementedError()

 

def delete(self, context, volume_id):

“””We do not support delete nbs volume now.”””

raise NotImplementedError()

 

def update(self, context, volume_id, fields):

raise NotImplementedError()

 

def get_snapshot(self, context, snapshot_id):

“””We do not support nbs volume snapshot now.”””

raise NotImplementedError()

 

def get_all_snapshots(self, context):

“””We do not support nbs volume snapshot now.”””

raise NotImplementedError()

 

def create_snapshot(self, context, volume_id, name, description):

“””We do not support nbs volume snapshot now.”””

raise NotImplementedError()

 

def create_snapshot_force(self, context, volume_id, name, description):

“””We do not support nbs volume snapshot now.”””

raise NotImplementedError()

 

def delete_snapshot(self, context, snapshot_id):

“””We do not support nbs volume snapshot now.”””

raise NotImplementedError()

 

def get_volume_encryption_metadata(self, context, volume_id):

“””We do not support for encrypting nbs volume snapshot now.”””

return {}

 

def get_volume_metadata(self, context, volume_id):

raise NotImplementedError()

 

def delete_volume_metadata(self, context, volume_id, key):

raise NotImplementedError()

 

def update_volume_metadata(self, context, volume_id,

metadata, delete=False):

raise NotImplementedError()

 

def get_volume_metadata_value(self, volume_id, key):

raise NotImplementedError()

 

def update_snapshot_status(self, context, snapshot_id, status):

“””We do not support nbs volume snapshot now.”””

raise NotImplementedError()

 

nova/virt/libvirt.py:

cfg.ListOpt(‘libvirt_volume_drivers’,

default=[

‘iscsi=nova.virt.libvirt.volume.LibvirtISCSIVolumeDriver’,

‘iser=nova.virt.libvirt.volume.LibvirtISERVolumeDriver’,

‘local=nova.virt.libvirt.volume.LibvirtVolumeDriver’,

‘fake=nova.virt.libvirt.volume.LibvirtFakeVolumeDriver’,

‘rbd=nova.virt.libvirt.volume.LibvirtNetVolumeDriver’,

‘sheepdog=nova.virt.libvirt.volume.LibvirtNetVolumeDriver’,

‘nfs=nova.virt.libvirt.volume.LibvirtNFSVolumeDriver’,

‘aoe=nova.virt.libvirt.volume.LibvirtAOEVolumeDriver’,

‘glusterfs=’nova.virt.libvirt.volume.LibvirtGlusterfsVolumeDriver’,

‘fibre_channel=nova.virt.libvirt.volume.LibvirtFibreChannelVolumeDriver’,

‘scality=nova.virt.libvirt.volume.LibvirtScalityVolumeDriver’,

‘nbs=nova.virt.libvirt.volume.LibvirtNBSVolumeDriver’,

],

help=’Libvirt handlers for remote volumes.’),

 

nova/virt/libvirt/volume.py:

class LibvirtNBSVolumeDriver(LibvirtBaseVolumeDriver):

“””Driver to attach NetEase Block Service volume to libvirt.”””

 

def __init__(self, connection):

“””Create back-end to NBS.”””

super(LibvirtNBSVolumeDriver,

self).__init__(connection, is_block_dev=False)

 

def connect_volume(self, connection_info, disk_info):

“””Returns xml for libvirt.”””

import ipdb;ipdb.set_trace()

conf = super(LibvirtNBSVolumeDriver,

self).connect_volume(connection_info,

disk_info)

 

conf.source_type = ‘block’

conf.source_path = connection_info[‘host_dev’]

conf.slot = disk_info[‘device’][‘slot’]

 

return conf

 

def disconnect_volume(self, connection_info, disk_dev):

“””Disconnect the volume.”””

pass

 

5.      剩余工作

剩下的工作主要包括:

  • 完善nbs插件代码:主要是要确认不同操作的时候试验代码能否满足要求,比如卸载nbs卷操作是否能用试验代码来完成
  • 清理旧的实现:包括挂载卷、卸载卷两个主要功能,以及较多的保证兼容性的冗余代码
  • 细节完善:包括为nbs新增的部分功能(带slot号挂载卷、支持卷的QoS设置、相关通知操作等),以及补充相关bug修复代码到nova的各种卷操作流程(如防止频繁挂卸载卷等)
  • 外围功能验证:支持带nbs情况下resize、离线迁移、强制重启、查询虚拟机详细信息可显示挂载的卷等功能
  • 兼容性验证及完善:支持带nbs情况下的其他功能如shelve、resume等等,以及已有nbs卷的兼容性问题(要支持虚拟机上挂载已有卷的情况下,使用修改后的代码完成各种生命周期操作,以及卸载卷操作等)

 

云计算与虚拟化

PPT下载地址:

github: https://github.com/aspirer/docfiles/blob/master/%E4%BA%91%E8%AE%A1%E7%AE%97%E4%B8%8E%E8%99%9A%E6%8B%9F%E5%8C%96.pptx?raw=true

内容:
}什么是云计算
}云计算发展现状
}云计算面对的问题
}什么是虚拟化
}主流虚拟化技术
}虚拟化中间件
}虚拟化技术面对的问题

 

之后又补充了和VMware的对比内容:

OpenStack vs VMware

PPT下载地址:

基于qemu guest agent的openstack kvm虚拟机监控

通过libvirt来实现在宿主机上获取kvm虚拟机内部的运行数据信息,python编写,使用了libvirt_qemu库和libvirt两个python库,除了qemu guest agent之外不需要在虚拟机内部跑其他agent即可获取大多数运维所需的监控项。
别的不多说,直接上源码。
github源码:
qemu guest agent相关patch(获取磁盘设备的realpath,以及获取指定目录所在磁盘的空间信息):
如果你的虚拟机是debian os,并且在虚拟机内安装了1.5.0+dfsg-5版本的qemu guest agent,可以直接用下面这个可执行的二进制文件替换掉/usr/sbin/qemu-ga,即可使用这两个patch的功能。
支持的监控项包括:
<metric name=”cpuUsage” unit=”Percent”/>
<metric name=”memUsage” unit=”Megabytes”/>
<metric name=”networkReceive” unit=”Kilobytes/Second”/>
<metric name=”networkTransfer” unit=”Kilobytes/Second”/>
<metric name=”diskUsage” unit=”Megabytes”/>
<metric name=”diskReadRequest” unit=”Count/Second”/>
<metric name=”diskWriteRequest” unit=”Count/Second”/>
<metric name=”diskReadRate” unit=”Kilobytes/Second”/>
<metric name=”diskWriteRate” unit=”Kilobytes/Second”/>
<metric name=”diskReadDelay” unit=”Milliseconds/Count”/>
<metric name=”diskWriteDelay” unit=”Milliseconds/Count”/>
<metric name=”diskPartition” unit=”all partitions infos”/>
<metric name=”loadavg_5″ unit=”Percent”/>
<metric name=”memUsageRate” unit=”Percent”/>

qemu-monitor-command & qemu monitor in openstack

instance-name.monitor的用途
首先我们注意到openstack中创建的每台KVM虚拟机,都会在/var/lib/libvirt/qemu/目录下生成一个instance-name.monitor socket文件
这个文件的用途是什么?
libvirt.xml里面以及用virsh dumpxml命令都看不到这个文件的配置,它是怎么创建出来的?
wangpan@xxyyzz8:~$ sudo ls /var/lib/libvirt/qemu/ l
srwxrxrx 1 libvirtqemu kvm             0 Aug 30  2012 instance000000a4.monitor
srwxrxrx 1 libvirtqemu kvm             0 Sep 17  2012 instance000001ec.monitor
srwxrxrx 1 libvirtqemu kvm             0 Oct  9  2012 instance00000217.monitor
用途:用来查看qemu运行状态以及与qemu进行交互,管理虚拟机,提供类似qemu命令行方式启动虚拟机的与虚拟机的交互操作
怎么创建的:可以查看libvirt的运行时配置文件/var/run/libvirt/qemu/instance-name.xml,打开可以看到如下内容:
<monitor path=’/var/lib/libvirt/qemu/instance-00000611.monitor’ json=’1′ type=’unix’/>
但是我们在openstack生成的libvirt.xml中又看不到这项配置,那它到底是怎么生成的?
普通列表项目看了libvirt的源码,在创建虚拟机的qemuProcessstart()的时候会先准备qemu监控字符设备‘MonitorChr’:
VIR_DEBUG(“Preparing monitor state”);
if (qemuProcessPrepareMonitorChr(driver, priv->monConfig, vm->def->name) < 0)
    goto cleanup;
这里就会增加monitor字符设备,类型为unix domain socket,文件路径为libvirt libdir+vm-name+.monitor,具体代码如下:
int
qemuProcessPrepareMonitorChr(struct qemud_driver *driver,
                             virDomainChrSourceDefPtr monConfig,
                             const char *vm)
{
    monConfig->type = VIR_DOMAIN_CHR_TYPE_UNIX;
    monConfig->data.nix.listen = true;
    if (virAsprintf(&monConfig->data.nix.path, “%s/%s.monitor”,
                    driver->libDir, vm) < 0) {
        virReportOOMError();
        return 1;
    }
    return 0;
}
最后libvirt生成qemu命令行参数的时候会把这个配置加进去:
VIR_DEBUG(“Building emulator command line”);
if (!(cmd = qemuBuildCommandLine(conn, driver, vm->def, priv->monConfig,
                                 priv->monJSON != 0, priv->qemuCaps,
                                 migrateFrom, stdin_fd, snapshot, vmop)))
    goto cleanup;
qemuBuildCommandLine():
……
if (monitor_chr) { /*monitor_chr就是priv->monConfig,所以这里走if分支*/
      char *chrdev;
      /* Use -chardev if it’s available */
      if (qemuCapsGet(qemuCaps, QEMU_CAPS_CHARDEV)) {
          virCommandAddArg(cmd, “-chardev”);
          if (!(chrdev = qemuBuildChrChardevStr(monitor_chr, “monitor”,
                                                qemuCaps)))
              goto error;
          virCommandAddArg(cmd, chrdev);
          VIR_FREE(chrdev);
          virCommandAddArg(cmd, “-mon”);
          virCommandAddArgFormat(cmd,
                                 “chardev=charmonitor,id=monitor,mode=%s”,
                                 monitor_json ? “control” : “readline”);
      } else {
          const char *prefix = NULL;
          if (monitor_json)
              prefix = “control,”;
          virCommandAddArg(cmd, “-monitor”);
          if (!(chrdev = qemuBuildChrArgStr(monitor_chr, prefix)))
              goto error;
          virCommandAddArg(cmd, chrdev);
          VIR_FREE(chrdev);
      }
  }
最终生成的qemu命令行信息为:
-chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/instance-00000611.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control
使用qemu-monitor-command查询、管理虚拟机
libvirt提供了qemu-monitor-command命令行及API,下面以命令行方式为例进行介绍:
$ sudo virsh help qemumonitorcommand
NAME
  qemumonitorcommand QEMU Monitor Command
SYNOPSIS
  qemumonitorcommand <domain> [–hmp] {[–cmd] <string>}…
DESCRIPTION
  QEMU Monitor Command
OPTIONS
  [–domain] <string>  domain name, id or uuid
  hmp            command is in human monitor protocol
  [–cmd] <string>  command
$ sudo virsh qemumonitorcommand ${instancename} hmp ‘info commands’
info balloon   show balloon information
info block   show the block devices
info blockjobs   show progress of ongoing block device operations
info blockstats   show block device statistics
info capture   show capture information
info chardev   show the character devices
info cpus   show infos for each CPU
info history   show the command line history
info irq   show the interrupts statistics (if available)
info jit   show dynamic compiler info
info kvm   show KVM information
info mem   show the active virtual memory mappings
info mice   show which guest mouse is receiving events
info migrate   show migration status
info mtree   show memory tree
info name   show the current VM name
info network   show the network state
info numa   show NUMA information
info pci   show PCI info
info pcmcia   show guest PCMCIA status
info pic   show i8259 (PIC) state
info profile   show profiling information
info qdm   show qdev device model list
info qtree   show device tree
info registers   show the cpu registers
info roms   show roms
info snapshots   show the currently saved VM snapshots
info spice   show the spice server status
info status   show the current VM status (running|paused)
info tlb   show virtual to physical memory mappings
info traceevents   show available traceevents & their state
info usb   show guest USB devices
info usbhost   show host USB devices
info usernet   show user network stack connection states
info uuid   show the current VM UUID
info version   show the version of QEMU
info vnc   show the vnc server status
$ sudo virsh qemumonitorcommand instance00000611 hmp ‘info vnc’
Server:
     address: 114.113.199.8:5900
        auth: none
Client: none
还有一些其他的管理类的操作,这里不一一列举,可参考:
另外在openstack Folsom版本中没有看到有用到这个monitor,没有看到这个Libvirt API被调用,不知道后续会不会有用处?个人感觉应该不会用到,因为这个monitor是libvirt自己生成的,跟openstack其实没有关系。

基于Qemu guest agent的kvm虚拟机监控调研

原文地址:http://aspirer2004.blog.163.com/blog/static/106764720136845622508/

文档地址:

Qemu guest agent调研

Qemu guest agent调研···· 1

  1. 原理分析···· 2
  2. 实现程度···· 3

2.1        已有功能··· 3

2.2        功能扩展方式··· 4

  1. 社区活跃度···· 7
  2. 实现监控方案的可行性···· 7

4.1        监控方案现状··· 7

4.2        当前方案存在的问题··· 7

4.3        采用qga方式的监控方案··· 8

4.4        改为qga方式需要做的工作··· 9

4.5        qga方式存在的问题··· 9

  1. 对网易私有云项目的其他用途···· 9

5.1        云主机内部操作系统状态检查··· 9

5.2        冻结云主机内部文件系统··· 9

  1. 类似agent比较···· 10

6.1        ovirt-guest-agent 10

 

 

 

 

 

 

 

 

 

 

 

本文主要是对Qemu guest agent调研结果的总结,主要内容如下:

  • Qemu guest agent的原理
  • Qemu guest agent的实现程度
  • Qemu guest agent的社区活跃度
  • 基于Qemu guest agent实现监控方案的可行性分析
  • Qemu guest agent对网易私有云项目的其他用途
  • Qemu guest agent风险分析

为了叙述方便,下文中将用qga来代替Qemu guest agent。

  1. 原理分析

qga是一个运行在虚拟机内部的普通应用程序(可执行文件名称默认为qemu-ga,服务名称默认为qemu-guest-agent),其目的是实现一种宿主机和虚拟机进行交互的方式,这种方式不依赖于网络,而是依赖于virtio-serial(默认首选方式)或者isa-serial,而QEMU则提供了串口设备的模拟及数据交换的通道,最终呈现出来的是一个串口设备(虚拟机内部)和一个unix socket文件(宿主机上)。

qga通过读写串口设备与宿主机上的socket通道进行交互,宿主机上可以使用普通的unix socket读写方式对socket文件进行读写,最终实现与qga的交互,交互的协议与qmp(QEMU Monitor Protocol)相同(简单来说就是使用JSON格式进行数据交换),串口设备的速率通常都较低,所以比较适合小数据量的交换。

QEMU virtio串口设备模拟参数:

/usr/bin/kvm(QEMU) \

……\

-device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x6 \

-device isa-serial,chardev=charserial1,id=serial1 \

-chardev socket,id=charchannel0,path=/var/lib/libvirt/qemu/test.agent,server,nowait \

-device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,\

name=com.163.spice.0

通过上面的参数就可以在宿主机上生成一个unix socket文件,路径为:/var/lib/libvirt/qemu/test.agent,同时在虚拟机内部生成一个serial设备,名字为com.163.spice.0,设备路径为:/dev/vport0p1,映射出来的可读性比较好的路径为:/dev/virtio-ports/com.163.spice.0,可以在运行qga的时候通过-p参数指定读写这个设备。

Libvirt支持QEMU串口相关配置,所以上述参数已经可以通过libvirt进行配置,且更简单直观,配置方式如下:

<channel type=’unix’>

<source mode=’bind’ path=’/var/lib/libvirt/qemu/test.agent’/>

<target type=’virtio’ name=’com.163.spice.0’/>

</channel>

需要注意的是libvirt-qemu:kvm用户要有权限读写’/var/lib/libvirt/qemu/test.agent’。

参考资料:http://wiki.qemu.org/Features/QAPI/GuestAgenthttp://wiki.libvirt.org/page/Qemu_guest_agent

  1. 实现程度
  • 已有功能

目前qga最新版本为1.5.50,linux已经实现下面的所有功能,windows仅支持加*的那些功能:

  • guest-sync-delimited*:宿主机发送一个int数字给qga,qga返回这个数字,并且在后续返回字符串响应中加入ascii码为0xff的字符,其作用是检查宿主机与qga通信的同步状态,主要用在宿主机上多客户端与qga通信的情况下客户端间切换过程的状态同步检查,比如有两个客户端A、B,qga发送给A的响应,由于A已经退出,目前B连接到qga的socket,所以这个响应可能被B收到,如果B连接到socket之后,立即发送该请求给qga,响应中加入了这个同步码就能区分是A的响应还是B的响应;在qga返回宿主机客户端发送的int数字之前,qga返回的所有响应都要忽略;
  • guest-sync*:与上面相同,只是不在响应中加入0xff字符;
  • guest-ping*:Ping the guest agent, a non-error return implies success;
  • guest-get-time*:获取虚拟机时间(返回值为相对于1970-01-01 in UTC,Time in nanoseconds.);
  • guest-set-time*:设置虚拟机时间(输入为相对于1970-01-01 in UTC,Time in nanoseconds.);
  • guest-info*:返回qga支持的所有命令;
  • guest-shutdown*:关闭虚拟机(支持halt、powerdown、reboot,默认动作为powerdown);
  • guest-file-open:打开虚拟机内的某个文件(返回文件句柄);
  • guest-file-close:关闭打开的虚拟机内的文件;
  • guest-file-read:根据文件句柄读取虚拟机内的文件内容(返回base64格式的文件内容);
  • guest-file-write:根据文件句柄写入文件内容到虚拟机内的文件;
  • guest-file-seek:Seek to a position in the file, as with fseek(), and return the current file position afterward. Also encapsulates ftell()’s functionality, just Set offset=0, whence=SEEK_CUR;
  • guest-file-flush:Write file changes bufferred in userspace to disk/kernel buffers;
  • guest-fsfreeze-status:Get guest fsfreeze state. error state indicates;
  • guest-fsfreeze-freeze:Sync and freeze all freezable, local guest filesystems;
  • guest-fsfreeze-thaw:Unfreeze all frozen guest filesystems;
  • guest-fstrim:Discard (or “trim”) blocks which are not in use by the filesystem;
  • guest-suspend-disk*:Suspend guest to disk;
  • guest-suspend-ram*:Suspend guest to ram;
  • guest-suspend-hybrid:Save guest state to disk and suspend to ram(This command requires the pm-utils package to be installed in the guest.);
  • guest-network-get-interfaces:Get list of guest IP addresses, MAC addresses and netmasks;
  • guest-get-vcpus:Retrieve the list of the guest’s logical processors;
  • guest-set-vcpus:Attempt to reconfigure (currently: enable/disable) logical processors inside the guest。

参考资料:源码

http://git.qemu.org/?p=qemu.git;a=blob;f=qga/qapi-schema.json;h=7155b7ab55fc4ef5336fd771ca06905c485fad62;hb=refs/heads/master

  • 功能扩展方式

qga功能扩展十分方便,只需要在qapi-schema.json文件中定义好功能名称、输入输出数据类型,然后在commands-posix.c里面增加对应的功能函数即可,下面的补丁即在qga中增加一个通过statvfs获取虚拟机磁盘空间信息的功能:

diff –git a/qga/commands-posix.c b/qga/commands-posix.c

index e199738..2f42a2f 100644

— a/qga/commands-posix.c

+++ b/qga/commands-posix.c

@@ -21,6 +21,7 @@

#include <stdio.h>

#include <string.h>

#include <sys/stat.h>

+#include <sys/statvfs.h>

#include <inttypes.h>

#include “qga/guest-agent-core.h”

#include “qga-qmp-commands.h”

@@ -1467,6 +1468,36 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)

}

#endif

 

+GuestFileSystemStatistics *qmp_guest_get_statvfs(const char *path, Error **errp)

+{

+    int ret;

+    GuestFileSystemStatistics *fs_stat;

+    struct statvfs *buf;

+    buf = g_malloc0(sizeof(struct statvfs));

+

+

+    ret = statvfs(path, buf);

+    if (ret < 0) {

+       error_setg_errno(errp, errno, “Failed to get statvfs”);

+       return NULL;

+    }

+

+    fs_stat = g_malloc0(sizeof(GuestFileSystemStatistics));

+    fs_stat->f_bsize = buf->f_bsize;

+    fs_stat->f_frsize = buf->f_frsize;

+    fs_stat->f_blocks = buf->f_blocks;

+    fs_stat->f_bfree = buf->f_bfree;

+    fs_stat->f_bavail = buf->f_bavail;

+    fs_stat->f_files = buf->f_files;

+    fs_stat->f_ffree = buf->f_ffree;

+    fs_stat->f_favail = buf->f_favail;

+    fs_stat->f_fsid = buf->f_fsid;

+    fs_stat->f_flag = buf->f_flag;

+    fs_stat->f_namemax = buf->f_namemax;

+

+    return fs_stat;

+}

+

/* register init/cleanup routines for stateful command groups */

void ga_command_state_init(GAState *s, GACommandState *cs)

{

diff –git a/qga/qapi-schema.json b/qga/qapi-schema.json

index 7155b7a..a071c3f 100644

— a/qga/qapi-schema.json

+++ b/qga/qapi-schema.json

@@ -638,3 +638,52 @@

{ ‘command’: ‘guest-set-vcpus’,

‘data’:    {‘vcpus’: [‘GuestLogicalProcessor’] },

‘returns’: ‘int’ }

+

+##

+# @GuestFileSystemStatistics:

+#

+# Information about guest file system statistics.

+#

+# @f_bsize: file system block size.

+#

+# @f_frsize: fragment size.

+#

+# @f_blocks: size of fs in f_frsize units.

+#

+# @f_bfree: free blocks.

+#

+# @f_bavail: free blocks for non-root.

+#

+# @f_files: inodes.

+#

+# @f_ffree: free inodes.

+#

+# @f_favail: free inodes for non-root.

+#

+# @f_fsid: file system id.

+#

+# @f_flag: mount flags

+#

+# @f_namemax: maximum filename length.

+#

+# Since 1.5.10(NetEase)

+##

+{ ‘type’: ‘GuestFileSystemStatistics’,

+  ‘data’: { ‘f_bsize’: ‘int’, ‘f_frsize’: ‘int’, ‘f_blocks’: ‘int’,

+            ‘f_bfree’: ‘int’, ‘f_bavail’: ‘int’, ‘f_files’: ‘int’,

+            ‘f_ffree’: ‘int’, ‘f_favail’: ‘int’, ‘f_fsid’: ‘int’,

+            ‘f_flag’: ‘int’, ‘f_namemax’: ‘int’} }

+

+##

+# @guest-get-statvfs:

+#

+# Get the information about guest file system statistics by statvfs.

+#

+# Returns: @GuestFileSystemStatistics.

+#

+# Since 1.5.10(NetEase)

+##

+{ ‘command’: ‘guest-get-statvfs’,

+  ‘data’:    { ‘path’: ‘str’ },

+  ‘returns’: ‘GuestFileSystemStatistics’ }

+

中间复杂的类型定义代码,以及头文件包含关系处理都由一个python脚本在编译的时候动态生成出来,这对开发人员来说是非常方便的,开发人员在扩展功能的时候只需要关注输入、输出的数据类型,以及功能的函数内容即可。

参考资料:源码及guest-get-time功能提交记录

http://git.qemu.org/?p=qemu.git;a=commitdiff;h=6912e6a94cb0a1d650271103efbc3ac2299e4fd0

  1. 社区活跃度

QEMU社区从2011年7月20号开始在QEMU代码仓库中增加qga功能,最近一次提交在2013年5月18号,总共有100多次提交记录,代码维护人员主要来自redhat和IBM,社区的活跃度不高,但是QEMU本身的提交记录从2003年至今已有27200多条,还是比较活跃的,qga的功能及代码都比较简单,也是活跃度不高的一个重要原因。

QEMU代码仓库地址:git clone git://git.qemu-project.org/qemu.git

qga代码位于QEMU代码的根目录下的qga目录中。

参考资料:代码仓库git log

  1. 实现监控方案的可行性
  • 监控方案现状

目前云主机监控的实现方法是,在创建云主机的过程中,增加监控脚本及其配置文件、定时任务及监控信息推送配置文件的注入过程,包括四个文件,其中监控信息推送配置文件(/etc/vm_monitor/info)由管理平台根据云主机所属用户的注册信息以及监控平台相关配置生成,并传入创建云主机的API来实现文件的注入,监控脚本(/etc/vm_monitor/send_monitor_data.py)及其配置文件(/etc/vm_monitor/monitor_settings.xml)、定时任务文件(/etc/cron.d/inject_cron_job)是包含在NVS经过base64编码后的监控脚本文件inject_files.json中。

工作模式为,在root账户增加定时任务inject_cron_job,其中有一条任务为:root su -c ‘python /etc/vm_monitor/send_monitor_data.py’ > /dev/null 2>&1,也即每60s收集并推送一次监控信息给监控平台。

  • 当前方案存在的问题
  • 依赖云主机内部的python解释器
  • 云主机必须存在root账户
  • 依赖NVS文件注入功能;并且为了注入这些监控文件对nova的改动也比较大,也无法与社区同步;windows镜像也会注入这些无用的文件,可能导致一些意想不到的问题;另外如果有的镜像的操作系统不在第一个分区上,则注入的监控文件会失效
  • 已经运行的云主机内部的监控相关文件更新困难,导致新监控项的添加、推送周期、推送地址等的修改也比较困难,灵活性较差
  • Nova中base64编码的注入脚本的代码可读性很差,代码更新及维护困难
  • 定位问题一般都需要登录到云主机内部进行,对于采用密钥对登录的云主机来说定位问题比较困难
  • 采用qga方式的监控方案

首先为每个云主机增加virtio-serial的配置,这个只需要修改生成libvirt配置文件的代码即可,并且应该可以提交给社区;其次需要在虚拟机内部安装qga服务;最后需要在宿主机上新增一个服务进程(这里暂定为monitor服务),用来通过与qga交互从云主机内部获取监控信息;总的模块交互流程如下:

图表 1 云主机创建流程中的监控相关操作

monitor服务单次监控信息获取及推送流程如下:

图表 2 单次监控数据获取及推送流程图

  • 改为qga方式需要做的工作
  • 需要扩展qga的功能,增加获取文件系统信息的功能(1人天)
  • 为qga打包的相关工作(3~5人天)
  • 需要重构监控信息获取脚本,把读本地/proc目录相关文件改为通过qga读文件(3~5人天)
  • 计算节点新增monitor服务(5~10人天)
  • nova代码修改,包括新增virtio-serial配置生成流程以及去掉原有的监控文件注入流程(3人天)
  • 已有镜像需要更新,安装qga(1人天)
  • qga方式存在的问题
  • 与当前方案的兼容性问题:已创建的云主机仍然采用原有的监控方式进行数据推送,新创建的云主机则采用qga方式进行监控数据的推送(可以通过检查宿主机上没有socket文件来区分新创建还是已有云主机);监控项保持不变;
  • qga升级问题:除非需要增加读取云主机内部相关文件不能获取到相关信息的监控项,否则不需要特别对qga进行升级;如果确实需要升级,可以在云主机内部配置包含新版本qga的apt相关源,通过apt方式进行升级;
  • qga稳定性问题:已经简单对其进行过测试,文件读取功能稳定性没有发现问题(每秒读取一次,连续运行超过24小时,测试代码:https://github.com/aspirer/study/blob/master/qemu-guest-agent/poll_qemu_guest_agent.py
  • 监控项扩展问题:在不需要对qga进行升级的情况下,只需要升级monitor服务即可(已有云主机也不需要改动);如果需要同时升级qga(这种情况比较麻烦,如果不升级qga则新的监控项无法推送);
  • 安全问题:主要包括暴露在计算节点的socket文件以及暴露在云主机内部的virtio-serial,这两个文件或设备的安全性问题;外部的socket文件与云主机镜像文件类似,都是有权限控制的,普通用户无法访问;云主机内部的virtio-serial设备可能会被用户攻击,但由于其速率较低,所以对宿主机影响不大,主要的问题可能是用户会伪造监控文件,然后通过virtio-serial设备返回给monitor服务,导致报警异常,之前的监控文件注入方式比qga方式在这一问题上更严重,因为监控完全是通过注入的脚本在云主机内部获取并推送的,用户可以做任何修改,所以这个问题也应该不是问题;
  • 用户隐私保护问题:用户可能会担心我们使用qga获取云主机内部的某些敏感文件,但这个问题其实在云计算环境是无法完全避免的,即使不通过qga,我们也可以通过拷贝云主机镜像并重新创建新的云主机的方式获取云主机内部的任意文件,所以这应该也不是问题;
  • LXC支持问题:目前不支持LXC,只支持基于kvm的虚拟机。
  1. 对网易私有云项目的其他用途
  • 云主机内部操作系统状态检查

主要是心跳获取过程可以改为主动通过qga进行查询,而不是依赖注入的定时任务进行上报,这样会更准确及时一些。

  • 冻结云主机内部文件系统

可以用于保证快照操作的安全性*(不影响云主机正常运行,目前有潜在问题);可以通过扩展qga功能来保证文件系统一致性(sync功能)。

  1. 类似agent比较

该agent的原理与qga完全相同,是redhat公司为自己的OVirt虚拟化管理平台开发的与虚拟机交互的方案,与qga不同之处在于redhat采用了python作为其guest agent的开发语言,其支持的协议也是基于JSON格式的,并且它支持部分windows系统(但是配置起来比较复杂),另外它没有提供通用的文件读写功能,对我们的监控实现来说比较麻烦。其支持的功能列表可以在其主页查看到:http://www.ovirt.org/Guest_Agent

 

参考资料:http://www.ovirt.org/Category:Ovirt_guest_agent

qemu guest agent研究

1. qemu-guest-agent虚拟机内安装:

debian: 在/etc/apt/sources.list增加一行 deb http://ftp.cn.debian.org/debian sid main,sudo apt-get update,sudo apt-get install qemu-guest-agent
ubuntu: 在/etc/apt/sources.list增加一行 deb http://free.nchc.org.tw/ubuntu/ raring main universe,sudo apt-get update,sudo apt-get install qemu-guest-agent

2.安装卡住

  原因是如果你先修改了libvirt的配置文件,增加了virtio-serial的配置,并且name=’org.qemu.guest_agent.0’,那么由于在/etc/init.d/qemu-guest-agent启动脚本中没有增加-d参数,导致qemu-guest-agent处于前台启动过程,无法退出,导致安装卡住,解决方法是kill掉qemu-ga进程或者先安装qemu-guest-agent,之后再修改libvirt配置。

3.libvirt配置文件

     <channel type=’unix’>
       <source mode=’bind’ path=’/var/lib/libvirt/qemu/test.agent’/>
        <target type=’virtio’ name=’com.163.spice.0’/>
     </channel>
要注意path=’/var/lib/libvirt/qemu/test.agent’这个路径libvirt-qemu:kvm用户要有权限进行读写,否则虚拟机会启动失败。

4.无法与宿主机通信

要输出如下内容才基本可断定配置的serial可以通信:
root@debian:~# qemu-ga -v -p /dev/virtio-ports/com.163.spice.0
1372055252.431905: debug: received EOF
1372055252.532232: debug: received EOF
1372055252.632594: debug: received EOF
1372055252.732949: debug: received EOF
否则要查找原因。
我遇到一个特别奇怪的问题,如果我按照libvirt官方配置说明中的配置,
<channel type=’unix’>
      <source mode=’bind’ path=’/var/lib/libvirt/qemu/test.agent’/>
      <target type=’virtio’ name=’org.qemu.guest_agent.0’/>
</channel>
会导致/dev/virtio-ports/org.qemu.guest_agent.0无法用来与宿主机通信,改为com.163.guest_agent.0或者org.qemu.ga.0或者其他类似的名字,甚至不写(默认名称com.redhat.spice.0)都OK,我的libvirt版本是0.9.13,qemu版本(qemu-kvm  1.1.2+dfsg-2),虚拟机内核版本(Linux debian 3.2.0-3-amd64/Linux ubuntu 3.2.0-29-generic)。
这个问题的原因是如果不改名,libvirt就会自己连接到这个socket上,所以如果你不想让libvirt连接,就得改掉默认的名称。详见http://wiki.libvirt.org/page/Qemu_guest_agent(Configure guest agent without libvirt interference)

5. 依赖的内核模块(virtio_console)

debian wheezy 3.2内核编译处理的qemu-guest-agent:https://github.com/aspirer/study/blob/master/qemu-guest-agent/qemu-ga

—————————————————————————————-

qemu编译:

apt-get install libzip-dev libsdl1.2-dev  uml-utilities  dh-autoreconf  bridge-utils libpixman-1-dev
可选安装包(不确定是否需要):build-essential
./configure –target-list=x86_64-softmmu –prefix=/usr –localstatedir=/var –sysconfdir=/etc –enable-debug
make或者只编译qemu-guest-agent: make qemu-ga