1. 程式人生 > >Windows下Libvirt Java API使用教程(二)

Windows下Libvirt Java API使用教程(二)

libvirt的管理單位是單個主機,所以探測和監控介面所能獲取的資訊的最大範圍也是主機。所以先從主機入手,驗證libvirt介面。主機(libvirt所在管理節點)探測相關介面驗證程式碼如下:

   @Before
	public void init() {
		System.setProperty("jna.library.path",
				"D:/Git-Repo/git/libvirt-java/libvirt-java/src/test/java/kubi/coder/");
		try {
			xenConn = new Connect("xen+tcp://10.4.55.203/");
			// system代表擁有系統許可權/session是使用者許可權
kvmConn = new Connect("qemu+tcp://10.4.54.10/system"); } catch (LibvirtException e) { e.printStackTrace(); } } /** * 主機資訊探測介面驗證,驗證可以獲取的主機屬性和監控指標,分別考慮Xen環境和KVM環境 * * * @author lihzh * @date 2012-5-15 下午1:28:00 */ @Test public void testDetectHost() { // KVM doDetectHost(kvmConn);
// XEN doDetectHost(xenConn); } /** * 執行探測主機測試函式 * * @param conn * @author lihzh * @date 2012-5-15 下午1:37:37 */ private void doDetectHost(Connect conn) { try { // Returns the free memory for the connection // System.out.println("FreeMemory: " + conn.getFreeMemory());// 不支援 // Returns the system hostname on which the hypervisor is running.
// (the result of the gethostname(2) system call) // If we are connected to a remote system, // then this returns the hostname of the remote system System.out.println("Host name: " + conn.getHostName()); // Gets the name of the Hypervisor software used. System.out.println("Type: " + conn.getType()); // Gets the version level of the Hypervisor running. This may work // only with hypervisor call, i.e. with priviledged access to the // hypervisor, not with a Read-Only connection. If the version can't // be extracted by lack of capacities returns 0. // Returns: // major * 1,000,000 + minor * 1,000 + release System.out.println(conn.getVersion()); NodeInfo nodeInfo = conn.nodeInfo(); System.out.println("the number of active CPUs: " + nodeInfo.cpus); System.out.println("number of core per socket: " + nodeInfo.cores); System.out.println("memory size in kilobytes: " + nodeInfo.memory); System.out.println("expected CPU frequency: " + nodeInfo.mhz); System.out.println("string indicating the CPU model: " + nodeInfo.model); System.out.println("the number of NUMA cell, 1 for uniform: " + nodeInfo.nodes); System.out.println("number of CPU socket per node: " + nodeInfo.sockets); System.out.println("number of threads per core: " + nodeInfo.threads); System.out .println("the total number of CPUs supported but not necessarily active in the host.: " + nodeInfo.maxCpus()); // for (String interName : conn.listInterfaces()) { // System.out.println(interName); // } 不支援 // Provides the list of names of defined interfaces on this host // for (String interName : conn.listDefinedInterfaces()) { // System.out.println(interName); // } // 不支援 // Lists the active networks. for (String networkName : conn.listNetworks()) { System.out.println("Network name: " + networkName); } // Lists the names of the network filters for (String networkFilterName : conn.listNetworkFilters()) { System.out.println("Network filter name: " + networkFilterName); } System.out.println(conn.getCapabilities()); } catch (LibvirtException e) { e.printStackTrace(); } }

分別在KVM和XEN環境下測試了libvirt介面,測試結果如下:

Host name: s5410
Type: QEMU
9001
the number of active CPUs: 64
number of core per socket: 8
memory size in kilobytes: 49444896
expected CPU frequency: 2131
string indicating the CPU model: x86_64
the number of NUMA cell, 1 for uniform: 1
number of CPU socket per node: 4
number of threads per core: 2
the total number of CPUs supported but not necessarily active in the host.: 64
Network name: hello
Network name: default
Network filter name: no-other-l2-traffic
Network filter name: allow-dhcp
Network filter name: allow-dhcp-server
Network filter name: no-other-rarp-traffic
Network filter name: no-mac-spoofing
Network filter name: qemu-announce-self-rarp
Network filter name: clean-traffic
Network filter name: no-arp-spoofing
Network filter name: allow-ipv4
Network filter name: no-ip-spoofing
Network filter name: qemu-announce-self
Network filter name: allow-arp
Network filter name: no-mac-broadcast
Network filter name: allow-incoming-ipv4
Network filter name: no-ip-multicast
<capabilities>

  <host>
    <uuid>30b940dd-f79a-21a2-82d5-ddc1b1b4a7e4</uuid>
    <cpu>
      <arch>x86_64</arch>
      <model>core2duo</model>
      <topology sockets='4' cores='8' threads='2'/>
      <feature name='lahf_lm'/>
      <feature name='rdtscp'/>
      <feature name='pdpe1gb'/>
      <feature name='popcnt'/>
      <feature name='x2apic'/>
      <feature name='sse4.2'/>
      <feature name='sse4.1'/>
      <feature name='dca'/>
      <feature name='xtpr'/>
      <feature name='cx16'/>
      <feature name='tm2'/>
      <feature name='est'/>
      <feature name='vmx'/>
      <feature name='ds_cpl'/>
      <feature name='pbe'/>
      <feature name='tm'/>
      <feature name='ht'/>
      <feature name='ss'/>
      <feature name='acpi'/>
      <feature name='ds'/>
    </cpu>
    <migration_features>
      <live/>
      <uri_transports>
        <uri_transport>tcp</uri_transport>
      </uri_transports>
    </migration_features>
  </host>

  <guest>
    <os_type>hvm</os_type>
    <arch name='i686'>
      <wordsize>32</wordsize>
      <emulator>/usr/libexec/qemu-kvm</emulator>
      <machine>rhel5.4.0</machine>
      <machine canonical='rhel5.4.0'>pc</machine>
      <machine>rhel5.4.4</machine>
      <machine>rhel5.5.0</machine>
      <machine>rhel5.6.0</machine>
      <domain type='qemu'>
      </domain>
      <domain type='kvm'>
        <emulator>/usr/libexec/qemu-kvm</emulator>
      </domain>
    </arch>
    <features>
      <cpuselection/>
      <pae/>
      <nonpae/>
      <acpi default='on' toggle='yes'/>
      <apic default='on' toggle='no'/>
    </features>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='x86_64'>
      <wordsize>64</wordsize>
      <emulator>/usr/libexec/qemu-kvm</emulator>
      <machine>rhel5.4.0</machine>
      <machine canonical='rhel5.4.0'>pc</machine>
      <machine>rhel5.4.4</machine>
      <machine>rhel5.5.0</machine>
      <machine>rhel5.6.0</machine>
      <domain type='qemu'>
      </domain>
      <domain type='kvm'>
        <emulator>/usr/libexec/qemu-kvm</emulator>
      </domain>
    </arch>
    <features>
      <cpuselection/>
      <acpi default='on' toggle='yes'/>
      <apic default='on' toggle='no'/>
    </features>
  </guest>

</capabilities>

Host name: s55203
Type: Xen
3001000
the number of active CPUs: 32
number of core per socket: 8
memory size in kilobytes: 50276352
expected CPU frequency: 1995
string indicating the CPU model: x86_64
the number of NUMA cell, 1 for uniform: 1
number of CPU socket per node: 2
number of threads per core: 2
the total number of CPUs supported but not necessarily active in the host.: 32
Network name: default
Network filter name: allow-dhcp-server
Network filter name: qemu-announce-self-rarp
Network filter name: no-arp-spoofing
Network filter name: allow-arp
Network filter name: no-ip-multicast
Network filter name: no-other-rarp-traffic
Network filter name: allow-incoming-ipv4
Network filter name: no-mac-spoofing
Network filter name: allow-ipv4
Network filter name: no-ip-spoofing
Network filter name: clean-traffic
Network filter name: qemu-announce-self
Network filter name: no-other-l2-traffic
Network filter name: allow-dhcp
Network filter name: no-mac-broadcast
<capabilities>

  <host>
    <cpu>
      <arch>x86_64</arch>
      <features>
        <vmx/>
      </features>
    </cpu>
    <migration_features>
      <live/>
      <uri_transports>
        <uri_transport>xenmigr</uri_transport>
      </uri_transports>
    </migration_features>
  </host>

  <guest>
    <os_type>xen</os_type>
    <arch name='x86_64'>
      <wordsize>64</wordsize>
      <emulator>/usr/lib64/xen/bin/qemu-dm</emulator>
      <machine>xenpv</machine>
      <domain type='xen'>
      </domain>
    </arch>
  </guest>

  <guest>
    <os_type>xen</os_type>
    <arch name='i686'>
      <wordsize>32</wordsize>
      <emulator>/usr/lib64/xen/bin/qemu-dm</emulator>
      <machine>xenpv</machine>
      <domain type='xen'>
      </domain>
    </arch>
    <features>
      <pae/>
    </features>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='i686'>
      <wordsize>32</wordsize>
      <emulator>/usr/lib64/xen/bin/qemu-dm</emulator>
      <loader>/usr/lib/xen/boot/hvmloader</loader>
      <machine>xenfv</machine>
      <domain type='xen'>
      </domain>
    </arch>
    <features>
      <pae/>
      <nonpae/>
      <acpi default='on' toggle='yes'/>
      <apic default='on' toggle='yes'/>
    </features>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='x86_64'>
      <wordsize>64</wordsize>
      <emulator>/usr/lib64/xen/bin/qemu-dm</emulator>
      <loader>/usr/lib/xen/boot/hvmloader</loader>
      <machine>xenfv</machine>
      <domain type='xen'>
      </domain>
    </arch>
    <features>
      <acpi default='on' toggle='yes'/>
      <apic default='on' toggle='yes'/>
    </features>
  </guest>

</capabilities>
  • 注1:標註不支援的,是在當前環境當前libvirt版本下,執行會報: unsupported in sys interface的介面。
  • 注2:名詞解釋
    • hvm:gives similar information but when running a 32 bit OS fully virtualized with Xen using the hvm support。
    • numa:For processors that support hyperthreading, this is the number of hyperthreads they have per core. On a machine that doesn’t support hyperthreading, this will be 1.

說實話,這麼多資訊中,筆者關注的不多,有很多甚至說不出其代表的含義,筆者關注只是cpu的個數,核心數,記憶體總量等直觀資訊。有就足以。

看完了主機,再看看虛擬機器。一個虛擬化環境中的核心資源自然是虛擬機器,所以其屬性和資訊也自然多很多,上測試程式碼:

/**
	 * 測試探測虛擬機器介面
	 * 
	 * @author lihzh
	 * @date 2012-5-16 上午11:14:20
	 */
	@Test
	public void testDetectDomains() {
		// KVM
		doDetectDomains(kvmConn);
		// XEN
		doDetectDomains(xenConn);
	}

        /**
	 * 執行探測虛擬機器測試函式
	 * 
	 * @param conn
	 * @author lihzh
	 * @date 2012-5-16 上午11:15:27
	 */
	private void doDetectDomains(Connect conn) {
		try {
			// Lists the active domains.(列出所有處於啟動(啟用)狀態的虛擬機器的id)
			for (int activeDomId : conn.listDomains()) {
				System.out.println("Active vm id: " + activeDomId);
				// 根據Id,探測各個虛擬機器的詳細資訊
				Domain domain = conn.domainLookupByID(activeDomId);
				// Gets the hypervisor ID number for the domain
				System.out.println("Domain id: " + domain.getID());
				// Gets the public name for this domain
				System.out.println("Domain name: " + domain.getName());
				// Gets the type of domain operation system.
				System.out.println("Domain os type: " + domain.getOSType());
				// Gets the UUID for this domain as string.
				System.out.println("Domain uuid: " + domain.getUUIDString());
				// Retrieve the maximum amount of physical memory allocated to a
				// domain.
				System.out.println("Domain max memory: "
						+ domain.getMaxMemory());
				// Provides the maximum number of virtual CPUs supported for the
				// guest VM. If the guest is inactive, this is basically the
				// same as virConnectGetMaxVcpus. If the guest is running this
				// will reflect the maximum number of virtual CPUs the guest was
				// booted with.
				System.out.println("Domain max vcpu: " + domain.getMaxVcpus());
				// Provides an XML description of the domain. The description
				// may be
				// reused later to relaunch the domain with createLinux().
				System.out.println("Domain xml description: "
						+ domain.getXMLDesc(0));
				System.out.println("Domain maxMen allowed: "
						+ domain.getInfo().maxMem);
				System.out.println("Domain memory: " + domain.getInfo().memory);
				// domain.getJobInfo()
				// 不支援
				System.out.println("Domain state: " + domain.getInfo().state);
				// Provides a boolean value indicating whether the network is
				// configured to be automatically started when the host machine
				// boots.
				System.out.println("Domain network autostart: "
						+ domain.getAutostart());
				// Extracts information about virtual CPUs of this domain
				for (VcpuInfo vcpuInfo : domain.getVcpusInfo()) {
					System.out.println("cpu: " + vcpuInfo.cpu);
					System.out.println("cpu time: " + vcpuInfo.cpuTime);
					System.out.println("cpu number: " + vcpuInfo.number);
					System.out.println("cpu state: " + vcpuInfo.state);
				}
			
				// 如果是KVM環境
				if (conn.getURI().startsWith("qemu")) {
					// This function returns block device (disk) stats for block
					// devices attached to the domain
					DomainBlockInfo blockInfo = domain
							.blockInfo("/opt/awcloud/instance/admin/"
									+ domain.getName() + "/disk");
					System.out.println("Disk Capacity: "
							+ blockInfo.getCapacity());
					System.out.println("Disk allocation: "
							+ blockInfo.getAllocation());
					System.out.println("Disk physical: "
							+ blockInfo.getPhysical());

					DomainBlockStats blockStats = domain.blockStats("vda");
					// 磁碟讀取請求總數
					System.out.println("read request num: " + blockStats.rd_req);
					// 磁碟讀取總bytes數
					System.out.println("read request num: " + blockStats.rd_bytes);
					// 磁碟寫入請求總數
					System.out.println("read request num: " + blockStats.wr_req);
					// 磁碟寫入總bytes數
					System.out.println("read request num: " + blockStats.wr_bytes);
				}

			}
			
			// 列出所有停止態的虛擬機器
			for (String name : conn.listDefinedDomains()) {
				System.out.println("Inactive domain name: " + name);
			}

		} catch (LibvirtException e) {
			e.printStackTrace();
		}
	}

迴圈較多,摘取部分測試結果如下:

Active vm id: 53
Domain id: 53
Domain name: i-546A099E
Domain os type: hvm
Domain uuid: e608560a-2c03-8e48-2e60-d0d01693f530
Domain max memory: 147456
Domain max vcpu: 1
Domain xml description: <domain type='xen' id='53'>
  <name>i-546A099E</name>
  <uuid>e608560a-2c03-8e48-2e60-d0d01693f530</uuid>
  <memory>131072</memory>
  <currentMemory>131072</currentMemory>
  <vcpu>1</vcpu>
  <os>
    <type>hvm</type>
    <loader>/usr/lib/xen/boot/hvmloader</loader>
    <boot dev='hd'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
  </features>
  <clock offset='utc'/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <devices>
    <emulator>/usr/lib64/xen/bin/qemu-dm</emulator>
    <disk type='file' device='disk'>
      <driver name='file'/>
      <source file='/opt/awcloud/instance/admin/i-546A099E/disk'/>
      <target dev='hda' bus='ide'/>
    </disk>
    <disk type='file' device='disk'>
      <driver name='file'/>
      <source file='/opt/awcloud/instance/admin/i-546A099E/disk2'/>
      <target dev='hdb' bus='ide'/>
    </disk>
    <interface type='bridge'>
      <mac address='d0:0d:54:6a:09:9e'/>
      <source bridge='xenbr0'/>
      <script path='vif-bridge'/>
      <target dev='vif53.0'/>
    </interface>
    <serial type='file'>
      <source path='/opt/awcloud/instance/admin/i-546A099E/console.log'/>
      <target port='0'/>
    </serial>
    <console type='file'>
      <source path='/opt/awcloud/instance/admin/i-546A099E/console.log'/>
      <target port='0'/>
    </console>
    <input type='tablet' bus='usb'/>
    <input type='mouse' bus='ps2'/>
    <graphics type='vnc' port='17237' autoport='no'/>
  </devices>
</domain>

Domain maxMen allowed: 147456
Domain memory: 139140
Domain state: VIR_DOMAIN_BLOCKED
Domain network autostart: false
cpu: 31
cpu time: 2225977676675
cpu number: 0
cpu state: VIR_VCPU_BLOCKED
Domain network autostart: false
Inactive domain name: i-46A70811
Inactive domain name: i-38C20705
Inactive domain name: i-498E09B2
Inactive domain name: null
Inactive domain name: null
Inactive domain name: null
Inactive domain name: null
Inactive domain name: null

結果分析: 結果中基本包含了一個虛擬機器組成的全部元素資訊。如果你想做一個監控系統,你可以發現這裡有

  • 虛擬機器的名字
  • 虛擬機器的Id
  • 虛擬機器的記憶體大小
  • 虛擬CPU個數
  • 虛擬機器磁碟檔案資訊,磁碟檔案的大小。甚至包括log等資訊。
  • 虛擬磁碟讀寫速率。
  • 虛擬機器網路裝置資訊。Mac地址,裝置型別等。
  • 虛擬機器網絡卡讀寫速率。

基本可以滿足一個監控系統的需求。 解釋一下上面的測試程式碼。libvirt Java API的入口基本都是通過Connect這個類,也就是首先建立與被管理主機之間的連線

Connect kvmConn = new Connect("qemu+tcp://10.4.54.10/system");

然後通過該連接獲取資訊:

conn.listDomains()

一個介面的如果需要接受引數:

conn.domainLookupByID(activeDomId)

肯定可以從其他的介面返回中找到答案:

for (int activeDomId : conn.listDomains())

只是有的獲取的直接,有可能需要解析xml格式的返回值來獲取需要引數值。比如:diskpathinterfacepath。 最後再簡單介紹一下管控介面:

  /**
	 * 測試虛擬機器的簡單操作
	 * 
	 * @author lihzh
	 * @date 2012-5-16 下午3:35:43
	 */
	@Test
	public void testControlVM() {
		try {
			Domain domain = kvmConn.domainLookupByID(8);
			System.out.println("Domain state: " + domain.getInfo().state);
			domain.suspend();
			System.out.println("Domain state: " + domain.getInfo().state);
			for (int i = 0; i < 5; i++) {
				System.out.println("wait for: " + (5 - i));
				Thread.sleep(1000);
			}
			System.out.println("Resume vm.");
			domain.resume();
			System.out.println("Domain state: " + domain.getInfo().state);
		} catch (LibvirtException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

該用例主要測試了虛擬機器的掛起和恢復操作。這類操作是比較簡單的(因為無需引數)。一個複雜系統肯定需要包括虛擬機器建立等操作。libvirt主要通過xml表述來建立資源,首先需要生成被建立虛擬機器的完整描述,然後傳遞給建立的方法即可。描述的格式?呵呵,自然是上面測試結果給出的資料了。有興趣的,大家可以自己嘗試一下。libvirt的文件,還不完善,不過對於建立這樣重要的功能,還是給出了說明。大家也可以下載官方的手冊作為參考。

好了,相對於VMwareXenserver等虛擬化平臺的SDK,libvirt的Java API還是比較簡單的,上手很快,結構很簡單。當然,功能上可能還是有所欠缺,資訊量上,沒有其他的那麼充足。基於XML的方式操作資源,減少了介面的個數,使呼叫更直接,但是對開發人員卻增加了困難。不過仍不失為一個不錯的虛擬機器環境操作的API,尤其是針對KVM/XEN的環境來說,可謂不二的選擇。