1. 前言

云计算离不开虚拟化,虚拟化绕不开libvirt。

因为开发虚拟机监控程序,花了一些时间学习libvirt, 这是一篇用来熟悉libvirt的博客。

2. libvirt

按照官方主页的介绍,libvirt项目是:

  • 一套用于管理虚拟化平台的工具
  • 支持C、Python、Perl、Java及其他语言
  • 使用开源license
  • 支持KVM、QEMU、Xen、Virtuozzo、VMWare ESX、LXC、BHyve及其他驱动
  • 支持Linux、FreeBSD、Windows及macOS等操作系统
  • 被许多应用使用

在Linux平台上以C/S的形式存在,libvirtd程序作为服务端管理虚拟机,接收和解析客户端请求,客户端可以是virsh命令行工具,也可以是基于libvirt库自行开发的程序。

架构如下,图片来自维基百科:

可以看到libvirt对用户屏蔽了底层hypervisor,向上提供了统一的接口。

2.1 为什么不直接使用KVM

笔者在接触libvirtd前,一直都是直接使用qemu-kvm来玩虚拟机的,一般配置好参数和脚本后手动操作,控制虚拟机起停。

qemu本身也是一个模拟器,在Linux下可以利用kvm模块加速虚拟化,但qemu只是一个命令行工具,且参数多如牛毛,在用kvm调试安装黑苹果成功后,还是需要配置libvirtd实现开机自启动。

如果需要实现可编程的的虚拟机操作,我们需要:

  • 定义结构化的数据来虚拟机配置
  • 维护虚拟机的生命周期,包括创建、启动、停止、删除,并处理异常情况
  • 本地的Daemon维护虚拟机,向服务端提供API

开发和维护的工作量都不小,而libvirt不止做到这些,还提供一套虚拟化管理方案。

2.2 从virsh命令看libvirt

由于libvirt主要使用者都是云厂商的开发者,技术的应用者也不太可能公开分享实践经验。因此笔者在入门时从virsh命令开始,熟悉通过virsh命令操作虚拟机后,再从API库中寻找对应的接口完成功能。

virsh帮助命令输出

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
➜  ~ virsh

virsh [options]... [<command_string>]
virsh [options]... <command> [args...]

  options:
    -c | --connect=URI      hypervisor connection URI
    -d | --debug=NUM        debug level [0-4]
    -e | --escape <char>    set escape sequence for console
    -h | --help             this help
    -k | --keepalive-interval=NUM
                            keepalive interval in seconds, 0 for disable
    -K | --keepalive-count=NUM
                            number of possible missed keepalive messages
    -l | --log=FILE         output logging to file
    -q | --quiet            quiet mode
    -r | --readonly         connect readonly
    -t | --timing           print timing information
    -v                      short version
    -V                      long version
         --version[=TYPE]   version, TYPE is short or long (default short)
  commands (non interactive mode):

 Domain Management (help keyword 'domain')
    attach-device                  attach device from an XML file
    attach-disk                    attach disk device
    attach-interface               attach network interface
    autostart                      autostart a domain
    blkdeviotune                   Set or query a block device I/O tuning parameters.
    blkiotune                      Get or set blkio parameters
    blockcommit                    Start a block commit operation.
    blockcopy                      Start a block copy operation.
    blockjob                       Manage active block operations
    blockpull                      Populate a disk from its backing image.
    blockresize                    Resize block device of domain.
    change-media                   Change media of CD or floppy drive
    console                        connect to the guest console
    cpu-stats                      show domain cpu statistics
    create                         create a domain from an XML file
    define                         define (but don't start) a domain from an XML file
    desc                           show or set domain's description or title
    destroy                        destroy (stop) a domain
    detach-device                  detach device from an XML file
    detach-device-alias            detach device from an alias
    detach-disk                    detach disk device
    detach-interface               detach network interface
    domdisplay                     domain display connection URI
    domfsfreeze                    Freeze domain's mounted filesystems.
    domfsthaw                      Thaw domain's mounted filesystems.
    domfsinfo                      Get information of domain's mounted filesystems.
    domfstrim                      Invoke fstrim on domain's mounted filesystems.
    domhostname                    print the domain's hostname
    domid                          convert a domain name or UUID to domain id
    domif-setlink                  set link state of a virtual interface
    domiftune                      get/set parameters of a virtual interface
    domjobabort                    abort active domain job
    domjobinfo                     domain job information
    domname                        convert a domain id or UUID to domain name
    domrename                      rename a domain
    dompmsuspend                   suspend a domain gracefully using power management functions
    dompmwakeup                    wakeup a domain from pmsuspended state
    domuuid                        convert a domain name or id to domain UUID
    domxml-from-native             Convert native config to domain XML
    domxml-to-native               Convert domain XML to native config
    dump                           dump the core of a domain to a file for analysis
    dumpxml                        domain information in XML
    edit                           edit XML configuration for a domain
    event                          Domain Events
    inject-nmi                     Inject NMI to the guest
    iothreadinfo                   view domain IOThreads
    iothreadpin                    control domain IOThread affinity
    iothreadadd                    add an IOThread to the guest domain
    iothreaddel                    delete an IOThread from the guest domain
    send-key                       Send keycodes to the guest
    send-process-signal            Send signals to processes
    lxc-enter-namespace            LXC Guest Enter Namespace
    managedsave                    managed save of a domain state
    managedsave-remove             Remove managed save of a domain
    managedsave-edit               edit XML for a domain's managed save state file
    managedsave-dumpxml            Domain information of managed save state file in XML
    managedsave-define             redefine the XML for a domain's managed save state file
    memtune                        Get or set memory parameters
    perf                           Get or set perf event
    metadata                       show or set domain's custom XML metadata
    migrate                        migrate domain to another host
    migrate-setmaxdowntime         set maximum tolerable downtime
    migrate-getmaxdowntime         get maximum tolerable downtime
    migrate-compcache              get/set compression cache size
    migrate-setspeed               Set the maximum migration bandwidth
    migrate-getspeed               Get the maximum migration bandwidth
    migrate-postcopy               Switch running migration from pre-copy to post-copy
    numatune                       Get or set numa parameters
    qemu-attach                    QEMU Attach
    qemu-monitor-command           QEMU Monitor Command
    qemu-monitor-event             QEMU Monitor Events
    qemu-agent-command             QEMU Guest Agent Command
    reboot                         reboot a domain
    reset                          reset a domain
    restore                        restore a domain from a saved state in a file
    resume                         resume a domain
    save                           save a domain state to a file
    save-image-define              redefine the XML for a domain's saved state file
    save-image-dumpxml             saved state domain information in XML
    save-image-edit                edit XML for a domain's saved state file
    schedinfo                      show/set scheduler parameters
    screenshot                     take a screenshot of a current domain console and store it into a file
    set-lifecycle-action           change lifecycle actions
    set-user-password              set the user password inside the domain
    setmaxmem                      change maximum memory limit
    setmem                         change memory allocation
    setvcpus                       change number of virtual CPUs
    shutdown                       gracefully shutdown a domain
    start                          start a (previously defined) inactive domain
    suspend                        suspend a domain
    ttyconsole                     tty console
    undefine                       undefine a domain
    update-device                  update device from an XML file
    vcpucount                      domain vcpu counts
    vcpuinfo                       detailed domain vcpu information
    vcpupin                        control or query domain vcpu affinity
    emulatorpin                    control or query domain emulator affinity
    vncdisplay                     vnc display
    guestvcpus                     query or modify state of vcpu in the guest (via agent)
    setvcpu                        attach/detach vcpu or groups of threads
    domblkthreshold                set the threshold for block-threshold event for a given block device or it's backing chain element

 Domain Monitoring (help keyword 'monitor')
    domblkerror                    Show errors on block devices
    domblkinfo                     domain block device size information
    domblklist                     list all domain blocks
    domblkstat                     get device block stats for a domain
    domcontrol                     domain control interface state
    domif-getlink                  get link state of a virtual interface
    domifaddr                      Get network interfaces' addresses for a running domain
    domiflist                      list all domain virtual interfaces
    domifstat                      get network interface stats for a domain
    dominfo                        domain information
    dommemstat                     get memory statistics for a domain
    domstate                       domain state
    domstats                       get statistics about one or multiple domains
    domtime                        domain time
    list                           list domains

 Host and Hypervisor (help keyword 'host')
    allocpages                     Manipulate pages pool size
    capabilities                   capabilities
    cpu-baseline                   compute baseline CPU
    cpu-compare                    compare host CPU with a CPU described by an XML file
    cpu-models                     CPU models
    domcapabilities                domain capabilities
    freecell                       NUMA free memory
    freepages                      NUMA free pages
    hostname                       print the hypervisor hostname
    hypervisor-cpu-baseline        compute baseline CPU usable by a specific hypervisor
    hypervisor-cpu-compare         compare a CPU with the CPU created by a hypervisor on the host
    maxvcpus                       connection vcpu maximum
    node-memory-tune               Get or set node memory parameters
    nodecpumap                     node cpu map
    nodecpustats                   Prints cpu stats of the node.
    nodeinfo                       node information
    nodememstats                   Prints memory stats of the node.
    nodesuspend                    suspend the host node for a given time duration
    sysinfo                        print the hypervisor sysinfo
    uri                            print the hypervisor canonical URI
    version                        show version

 Interface (help keyword 'interface')
    iface-begin                    create a snapshot of current interfaces settings, which can be later committed (iface-commit) or restored (iface-rollback)
    iface-bridge                   create a bridge device and attach an existing network device to it
    iface-commit                   commit changes made since iface-begin and free restore point
    iface-define                   define an inactive persistent physical host interface or modify an existing persistent one from an XML file
    iface-destroy                  destroy a physical host interface (disable it / "if-down")
    iface-dumpxml                  interface information in XML
    iface-edit                     edit XML configuration for a physical host interface
    iface-list                     list physical host interfaces
    iface-mac                      convert an interface name to interface MAC address
    iface-name                     convert an interface MAC address to interface name
    iface-rollback                 rollback to previous saved configuration created via iface-begin
    iface-start                    start a physical host interface (enable it / "if-up")
    iface-unbridge                 undefine a bridge device after detaching its slave device
    iface-undefine                 undefine a physical host interface (remove it from configuration)

 Network Filter (help keyword 'filter')
    nwfilter-define                define or update a network filter from an XML file
    nwfilter-dumpxml               network filter information in XML
    nwfilter-edit                  edit XML configuration for a network filter
    nwfilter-list                  list network filters
    nwfilter-undefine              undefine a network filter
    nwfilter-binding-create        create a network filter binding from an XML file
    nwfilter-binding-delete        delete a network filter binding
    nwfilter-binding-dumpxml       network filter information in XML
    nwfilter-binding-list          list network filter bindings

 Networking (help keyword 'network')
    net-autostart                  autostart a network
    net-create                     create a network from an XML file
    net-define                     define an inactive persistent virtual network or modify an existing persistent one from an XML file
    net-destroy                    destroy (stop) a network
    net-dhcp-leases                print lease info for a given network
    net-dumpxml                    network information in XML
    net-edit                       edit XML configuration for a network
    net-event                      Network Events
    net-info                       network information
    net-list                       list networks
    net-name                       convert a network UUID to network name
    net-start                      start a (previously defined) inactive network
    net-undefine                   undefine a persistent network
    net-update                     update parts of an existing network's configuration
    net-uuid                       convert a network name to network UUID

 Node Device (help keyword 'nodedev')
    nodedev-create                 create a device defined by an XML file on the node
    nodedev-destroy                destroy (stop) a device on the node
    nodedev-detach                 detach node device from its device driver
    nodedev-dumpxml                node device details in XML
    nodedev-list                   enumerate devices on this host
    nodedev-reattach               reattach node device to its device driver
    nodedev-reset                  reset node device
    nodedev-event                  Node Device Events

 Secret (help keyword 'secret')
    secret-define                  define or modify a secret from an XML file
    secret-dumpxml                 secret attributes in XML
    secret-event                   Secret Events
    secret-get-value               Output a secret value
    secret-list                    list secrets
    secret-set-value               set a secret value
    secret-undefine                undefine a secret

 Snapshot (help keyword 'snapshot')
    snapshot-create                Create a snapshot from XML
    snapshot-create-as             Create a snapshot from a set of args
    snapshot-current               Get or set the current snapshot
    snapshot-delete                Delete a domain snapshot
    snapshot-dumpxml               Dump XML for a domain snapshot
    snapshot-edit                  edit XML for a snapshot
    snapshot-info                  snapshot information
    snapshot-list                  List snapshots for a domain
    snapshot-parent                Get the name of the parent of a snapshot
    snapshot-revert                Revert a domain to a snapshot

 Storage Pool (help keyword 'pool')
    find-storage-pool-sources-as   find potential storage pool sources
    find-storage-pool-sources      discover potential storage pool sources
    pool-autostart                 autostart a pool
    pool-build                     build a pool
    pool-create-as                 create a pool from a set of args
    pool-create                    create a pool from an XML file
    pool-define-as                 define a pool from a set of args
    pool-define                    define an inactive persistent storage pool or modify an existing persistent one from an XML file
    pool-delete                    delete a pool
    pool-destroy                   destroy (stop) a pool
    pool-dumpxml                   pool information in XML
    pool-edit                      edit XML configuration for a storage pool
    pool-info                      storage pool information
    pool-list                      list pools
    pool-name                      convert a pool UUID to pool name
    pool-refresh                   refresh a pool
    pool-start                     start a (previously defined) inactive pool
    pool-undefine                  undefine an inactive pool
    pool-uuid                      convert a pool name to pool UUID
    pool-event                     Storage Pool Events

 Storage Volume (help keyword 'volume')
    vol-clone                      clone a volume.
    vol-create-as                  create a volume from a set of args
    vol-create                     create a vol from an XML file
    vol-create-from                create a vol, using another volume as input
    vol-delete                     delete a vol
    vol-download                   download volume contents to a file
    vol-dumpxml                    vol information in XML
    vol-info                       storage vol information
    vol-key                        returns the volume key for a given volume name or path
    vol-list                       list vols
    vol-name                       returns the volume name for a given volume key or path
    vol-path                       returns the volume path for a given volume name or key
    vol-pool                       returns the storage pool for a given volume key or path
    vol-resize                     resize a vol
    vol-upload                     upload file contents to a volume
    vol-wipe                       wipe a vol

 Virsh itself (help keyword 'virsh')
    cd                             change the current directory
    echo                           echo arguments
    exit                           quit this interactive terminal
    help                           print help
    pwd                            print the current directory
    quit                           quit this interactive terminal
    connect                        (re)connect to hypervisor

在virsh的帮助命令中,所有的命令被划分为以下几类:

  • domain:虚拟机管理命令,domain对应虚拟机,libvirt使用xml描述虚拟机配置。需要首先通过define将虚拟机导入libvirtd,然后才能执行start、shutdown、destroy等开机、关机、强制关机操作,domain相关的命令接收ID或Name作为参数(在每台宿主机上需唯一)。domain相关命令对应API中Domain对象的方法集合,我们首选需要获取到一个domain引用,然后才能执行操作。
  • monitor:监控命令,可获取domain的配置、运行状态、统计数据等。
  • host:宿主机管理命令,用于获取和操作宿主机。
  • interface:网卡管理命令,比较少用,一般自行管理网络,使用VXLAN、Bridge、TUN/TAP将虚拟机接入用户网络。
  • filter:防火墙管理命令,可读取xml格式定义等防火墙规则,按虚拟机网卡配置防火墙。
  • network:网络相关命令,这里指的是libvirt的网络,默认使用Bridge和TUN/TAP将虚拟机加入宿主机网络,使用DHCP和iptables为虚拟机提供网络。
  • nodedev:宿主机设备管理命令,可将宿主机设备,例如GPU、USB、PCIe设备等分配给虚拟机。
  • secret:密钥管理命令。
  • snapshot:快照管理命令。
  • pool:存储池管理命令,一个存储池内可存放多个卷。
  • volume:数据卷管理命令。

virsh命令基于libvirt库开发的,因为libvirt有着良好的API架构,熟悉virsh命令对使用API有很大的帮助。

2.3 API

官方文档链接:Reference Manual for libvirt

在目录中我们可以看到与virsh命令几乎一一对应的API。

libvirt使用C语言编写,提供稳定的C API,对其他语言的支持也是通过C API的绑定实现的,因此本地需要安装相关的C开发库,并运行libvirtd守护进程。

以Go语言和CentOS 7为例,官方Go语言库为:libvirt-go,与C库版本同步向后兼容到v1.2.0,可用于生产环境。

开发环境需要安装gcc、libvirt、libvirt-devel、centos-release-qemu-ev等,该库通过CGO调用libvrt C库,访问本地的UNIX套接字来与libvirtd通信。因此不可避免需要开发本地Daemon程序,相当于在libvirtd基础上再封装一层,但这也方便操作NFS、VXLAN、系统镜像等,实现更多自定义功能。

以获取虚拟机运行状态为例,流程通常为:

获取libvirt连接 -> 按ID获取domain -> 执行操作 -> 释放domain

如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
conn, err := libvirt.NewConnect("qemu:///system")
if err != nil {
    ...
}
defer conn.Close()
doms, err := conn.ListAllDomains(libvirt.CONNECT_LIST_DOMAINS_ACTIVE)
if err != nil {
    ...
}
fmt.Printf("%d running domains:\n", len(doms))
for _, dom := range doms {
    name, err := dom.GetName()
    if err == nil {
        fmt.Printf("  %s\n", name)
    }
    dom.Free()
}

我们可以把常用的操作封装为函数,确保所有成功打开的连接和domain都被正确释放。

有CGO的地方,就有纯GO实现。digitalocean开源了他们内部使用的libvirt库:go-libvirt,这个库通过libvirt的RPC接口与守护进程通信,不需要引用C库,可通过网络远程调用libvirtd,唯一的缺点是不稳定。

2.4 虚拟机状态

libvirt-go提供的虚拟机状态分为当前状态state与导致当前状态的原因reason,由于含义都在源码注释中,下面整理了英文注释:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
 * virDomainState:
 *
 * A domain may be in different states at a given point in time
 */
typedef enum {
    VIR_DOMAIN_NOSTATE = 0,     /* no state */
    VIR_DOMAIN_RUNNING = 1,     /* the domain is running */
    VIR_DOMAIN_BLOCKED = 2,     /* the domain is blocked on resource */
    VIR_DOMAIN_PAUSED  = 3,     /* the domain is paused by user */
    VIR_DOMAIN_SHUTDOWN= 4,     /* the domain is being shut down */
    VIR_DOMAIN_SHUTOFF = 5,     /* the domain is shut off */
    VIR_DOMAIN_CRASHED = 6,     /* the domain is crashed */
    VIR_DOMAIN_PMSUSPENDED = 7, /* the domain is suspended by guest
                                   power management */

# ifdef VIR_ENUM_SENTINELS
    VIR_DOMAIN_LAST
    /*
     * NB: this enum value will increase over time as new events are
     * added to the libvirt API. It reflects the last state supported
     * by this version of the libvirt API.
     */
# endif
} virDomainState;

typedef enum {
    VIR_DOMAIN_NOSTATE_UNKNOWN = 0,

# ifdef VIR_ENUM_SENTINELS
    VIR_DOMAIN_NOSTATE_LAST
# endif
} virDomainNostateReason;

typedef enum {
    VIR_DOMAIN_RUNNING_UNKNOWN = 0,
    VIR_DOMAIN_RUNNING_BOOTED = 1,          /* normal startup from boot */
    VIR_DOMAIN_RUNNING_MIGRATED = 2,        /* migrated from another host */
    VIR_DOMAIN_RUNNING_RESTORED = 3,        /* restored from a state file */
    VIR_DOMAIN_RUNNING_FROM_SNAPSHOT = 4,   /* restored from snapshot */
    VIR_DOMAIN_RUNNING_UNPAUSED = 5,        /* returned from paused state */
    VIR_DOMAIN_RUNNING_MIGRATION_CANCELED = 6,  /* returned from migration */
    VIR_DOMAIN_RUNNING_SAVE_CANCELED = 7,   /* returned from failed save process */
    VIR_DOMAIN_RUNNING_WAKEUP = 8,          /* returned from pmsuspended due to
                                               wakeup event */
    VIR_DOMAIN_RUNNING_CRASHED = 9,         /* resumed from crashed */
    VIR_DOMAIN_RUNNING_POSTCOPY = 10,       /* running in post-copy migration mode */

# ifdef VIR_ENUM_SENTINELS
    VIR_DOMAIN_RUNNING_LAST
# endif
} virDomainRunningReason;

typedef enum {
    VIR_DOMAIN_BLOCKED_UNKNOWN = 0,     /* the reason is unknown */

# ifdef VIR_ENUM_SENTINELS
    VIR_DOMAIN_BLOCKED_LAST
# endif
} virDomainBlockedReason;

typedef enum {
    VIR_DOMAIN_PAUSED_UNKNOWN = 0,      /* the reason is unknown */
    VIR_DOMAIN_PAUSED_USER = 1,         /* paused on user request */
    VIR_DOMAIN_PAUSED_MIGRATION = 2,    /* paused for offline migration */
    VIR_DOMAIN_PAUSED_SAVE = 3,         /* paused for save */
    VIR_DOMAIN_PAUSED_DUMP = 4,         /* paused for offline core dump */
    VIR_DOMAIN_PAUSED_IOERROR = 5,      /* paused due to a disk I/O error */
    VIR_DOMAIN_PAUSED_WATCHDOG = 6,     /* paused due to a watchdog event */
    VIR_DOMAIN_PAUSED_FROM_SNAPSHOT = 7, /* paused after restoring from snapshot */
    VIR_DOMAIN_PAUSED_SHUTTING_DOWN = 8, /* paused during shutdown process */
    VIR_DOMAIN_PAUSED_SNAPSHOT = 9,      /* paused while creating a snapshot */
    VIR_DOMAIN_PAUSED_CRASHED = 10,     /* paused due to a guest crash */
    VIR_DOMAIN_PAUSED_STARTING_UP = 11, /* the domain is being started */
    VIR_DOMAIN_PAUSED_POSTCOPY = 12,    /* paused for post-copy migration */
    VIR_DOMAIN_PAUSED_POSTCOPY_FAILED = 13, /* paused after failed post-copy */

# ifdef VIR_ENUM_SENTINELS
    VIR_DOMAIN_PAUSED_LAST
# endif
} virDomainPausedReason;

typedef enum {
    VIR_DOMAIN_SHUTDOWN_UNKNOWN = 0,    /* the reason is unknown */
    VIR_DOMAIN_SHUTDOWN_USER = 1,       /* shutting down on user request */

# ifdef VIR_ENUM_SENTINELS
    VIR_DOMAIN_SHUTDOWN_LAST
# endif
} virDomainShutdownReason;

typedef enum {
    VIR_DOMAIN_SHUTOFF_UNKNOWN = 0,     /* the reason is unknown */
    VIR_DOMAIN_SHUTOFF_SHUTDOWN = 1,    /* normal shutdown */
    VIR_DOMAIN_SHUTOFF_DESTROYED = 2,   /* forced poweroff */
    VIR_DOMAIN_SHUTOFF_CRASHED = 3,     /* domain crashed */
    VIR_DOMAIN_SHUTOFF_MIGRATED = 4,    /* migrated to another host */
    VIR_DOMAIN_SHUTOFF_SAVED = 5,       /* saved to a file */
    VIR_DOMAIN_SHUTOFF_FAILED = 6,      /* domain failed to start */
    VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT = 7, /* restored from a snapshot which was
                                           * taken while domain was shutoff */
    VIR_DOMAIN_SHUTOFF_DAEMON = 8,      /* daemon decides to kill domain
                                           during reconnection processing */
# ifdef VIR_ENUM_SENTINELS
    VIR_DOMAIN_SHUTOFF_LAST
# endif
} virDomainShutoffReason;

typedef enum {
    VIR_DOMAIN_CRASHED_UNKNOWN = 0,     /* crashed for unknown reason */
    VIR_DOMAIN_CRASHED_PANICKED = 1,    /* domain panicked */

# ifdef VIR_ENUM_SENTINELS
    VIR_DOMAIN_CRASHED_LAST
# endif
} virDomainCrashedReason;

typedef enum {
    VIR_DOMAIN_PMSUSPENDED_UNKNOWN = 0,

# ifdef VIR_ENUM_SENTINELS
    VIR_DOMAIN_PMSUSPENDED_LAST
# endif
} virDomainPMSuspendedReason;

typedef enum {
    VIR_DOMAIN_PMSUSPENDED_DISK_UNKNOWN = 0,

# ifdef VIR_ENUM_SENTINELS
    VIR_DOMAIN_PMSUSPENDED_DISK_LAST
# endif
} virDomainPMSuspendedDiskReason;

笔者按照枚举数值整理如下:

  • 0:nostate,无状态
  • 1:running,运行中
    • unknown:未知
    • booted:正常开机启动
    • migrated:从其他宿主机迁移后启动
    • restored:从状态文件恢复运行
    • fromSnapshot:从快照恢复运行
    • unpaused:从挂起状态恢复运行
    • migrationCanceled:取消迁移状态后恢复运行
    • saveCancel:取消保存后恢复运行
    • wakeup:唤醒后恢复运行
    • crashed:从crash状态恢复启动
    • postCopy:复制结束后恢复启动
  • 2:blocked,因为资源阻塞
    • unknown:未知
  • 3:pause,挂起
    • unkown:未知
    • user:用户主动执行挂起
    • migration:执行迁移导致的挂起
    • save:保存虚拟机导致的挂起
    • dump:dump虚拟机导致的挂起
    • IOError:磁盘IO错误导致的挂起
    • watchdog:看门狗事件导致的挂起
    • fromSnapshot:从快照恢复后挂起
    • shuttingDown:关机时挂起
    • snapshot:创建快照时挂起
    • crash:虚拟机crash导致的挂起
    • startingUp:虚拟机正在启动
    • postCopy:post-copy迁移导致的挂起
    • postCopyFaiied:post-copy失败后的挂起
  • 4:shutdown,正在关机
    • unknown:未知
    • user:用户主动关机
  • 5:shutoff,已关闭
    • unknown:未知
    • shutdown:正常关机
    • destroyed:强制关机
    • crashed:domain crash
    • migrated:已迁移到其他host
    • saved:已保存到文件
    • failed:domain无法启动
    • fromSnapshot:从domain关闭时生成的快照恢复
    • daemon:被守护进程终结
  • 6:crash,crash
    • unknown:未知
    • panicked:domain panic
  • 7:pmsuspend,由虚拟机的电源管理挂起
    • unknown:未知

3. 写在最后

笔者的负责的虚拟机监控程序涉及libvirt内容比较简单,基本仅限于上面的示例代码:获取虚拟机状态上报服务端。

状态通过调接口就可以获取,比较麻烦的是做相关测试来确定libvirtd状态与业务状态的转换关系。

如果未来有更多虚拟机相关的开发工作时,应该会再深入研究一些API内部实现。