「 Python3 から XML-RPC 経由で Python2.7 の libvirt を使って KVM 操作 」では XML-RPC サーバーを起動しておく必要があり、管理が必要でした。
今回は「 Python3 から Python2.7 モジュールの関数をコマンド (func_caller.py) 経由で呼ぶ 」で紹介した方法を利用して Python3 からコマンド (func_caller.py) 経由で Python2.7 の libvirt を使って KVM 操作をします。この方法だと XML-RPC サーバーを起動しておく必要はありません。
概要
イメージです。
Python2.7 の libvirt モジュールでは open() 関数で作成したオブジェクトのメソッドを呼んで GuestOS を操作するので、func_caller.py から libvirt モジュールを直接扱えません。
なので、func_caller.py からは「 Python3 から XML-RPC 経由で Python2.7 の libvirt を使って KVM 操作 」で使った mLibVirtConn モジュールを呼びます。
環境
- Ubuntu 12.04.4 LTS Server
- 「 Kvm インストール 」の手順でインストールした KVM
Python2.7 側の準備
パッケージインストール
$ sudo apt-get install python-libvirt
- 以下の内容の mLibVirtConn.py を適当なディレクトリに設置
#!/usr/bin/env python2.7 # coding: utf-8 ''' mLibVirtConn.py ~~~~~~~~~~~~~~~~~~~~~~~ :copyright: Copyright 2014 by Fishrimper. :license: BSD ''' from __future__ import unicode_literals import libvirt # Class for XML-RPC instance. class LibVirtConn: def __init__(self): self.__oConn = libvirt.open('qemu:///system') def __get_oDomain(self, xNameOrID): if isinstance(xNameOrID, unicode): return self.__oConn.lookupByName(xNameOrID) else: return self.__oConn.lookupByID(xNameOrID) def listDomainsID(self): return self.__oConn.listDomainsID() def listDefinedDomains(self): return self.__oConn.listDefinedDomains() def domain_name(self, xNameOrID): return self.__get_oDomain(xNameOrID).name() def domain_create(self, sName): return self.__oConn.lookupByName(sName).create() def domain_destroy(self, xNameOrID): return self.__get_oDomain(xNameOrID).destroy()
「 Python3 から XML-RPC 経由で Python2.7 の libvirt を使って KVM 操作 」の mLibVirtConn.py は unicode 文字列で処理するべき箇所をバイト文字列で処理してしまっていました。
後述の func_caller.py から mLibVirtConn モジュールをインポートして使う場合に、ちゃんと unicode で処理していないと都合が悪いので mLibVirtConn.py のそのあたりを修正してます。
- 以下の内容の func_caller.py を mLibVirtConn.py と同じディレクトリに設置 (mLibVirtConn へのモジュールパスが通っていれば別ディレクトリでも良いです。)
#!/usr/bin/env python2.7 # coding: utf-8 ''' func_caller.py ~~~~~~~~~~~~~~~~~~~~~~~ :copyright: Copyright 2014 by Fishrimper. :license: BSD ''' from __future__ import unicode_literals import argparse import importlib import inspect import types import json from pprint import pprint def callAndGetResult(ClassOrFunc, sArgsInJson): if sArgsInJson == None: return ClassOrFunc() else: oArgs = json.loads(sArgsInJson) if isinstance(oArgs, list): return ClassOrFunc(*oArgs) elif isinstance(oArgs, dict): return ClassOrFunc(**oArgs) else: raise Exception(oArgs) def main(): oParser = argparse.ArgumentParser() oParser.add_argument('module_name') oParser.add_argument('--class_name') oParser.add_argument('--class_init_args', help='class init args in json format.') oParser.add_argument('func_name') oParser.add_argument('--func_args', help='function args in json format.') oArgs = oParser.parse_args() mModule = importlib.import_module(oArgs.module_name) if oArgs.class_name == None: oFunc = getattr(mModule, oArgs.func_name) else: cClass = getattr(mModule, oArgs.class_name) assert inspect.isclass(cClass), oArgs oInstance = callAndGetResult(cClass, oArgs.class_init_args) oFunc = getattr(oInstance, oArgs.func_name) ltypeFuncs = [ types.TypeType, types.BuiltinFunctionType, types.FunctionType, types.MethodType, ] for typeFunc in ltypeFuncs: if isinstance(oFunc, typeFunc): break else: raise Exception(oArgs, type(oFunc)) oResult = callAndGetResult(oFunc, oArgs.func_args) print(json.dumps(oResult)) if __name__ == '__main__': main()
mLibVirtConn.py と同様に「 Python3 から Python2.7 モジュールの関数をコマンド (func_caller.py) 経由で呼ぶ 」の func_caller.py から文字列の処理のあたりを修正しています。
func_caller.py に実行権限もつけときます。
$ chmod +x func_caller.py
試しに func_caller.py 動かしてみます。
$ ./func_caller.py mLibVirtConn --class_name LibVirtConn listDomainsID [1]起動しているゲスト OS は ID 1 のみでした。
virsh コマンドで確認できる結果とちゃんと一致します。
$ sudo virsh list Id Name State ---------------------------------- 1 KvmGuest1 running
Python3 側
mPy27_func_caller.py 設置
「 Python3 から Python2.7 モジュールの関数をコマンド (func_caller.py) 経由で呼ぶ 」 の mPy27_func_caller.py を func_caller.py と同じディレクトリに設置します。
mPy27_func_caller.py を設置したディレクトリに移動
- Python3 を起動して Py27_func_caller のインスタンスを作成
$ python3 Python 3.2.3 (default, Feb 27 2014, 21:31:18) [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> >>> from mPy27_func_caller import Py27_func_caller >>> oPy27 = Py27_func_caller('./func_caller.py')
Py27_func_caller() の引数で func_caller.py のパスを指定します。
- 起動している KVM ゲスト OS の ID リスト取得
>>> oPy27.call(sModuleName='mLibVirtConn', sClassName='LibVirtConn', sFuncName='listDomainsID') [1]
起動している KVM ゲスト OS は 1個だけで、ID は 1 でした。
- 指定した ID の KVM ゲスト OS の名前を取得
>>> oPy27.call(sModuleName='mLibVirtConn', sClassName='LibVirtConn', sFuncName='domain_name', xFuncArgs={'xNameOrID': 1}) 'KvmGuest1'
ID 1 の KVM ゲスト OS の名前は KvmGuest1 でした。
- 停止している KVM ゲスト OS の名前リスト取得
>>> oPy27.call(sModuleName='mLibVirtConn', sClassName='LibVirtConn', sFuncName='listDefinedDomains') ['TestDesktop', 'KvmGuest3', 'KvmGuest2']
停止している KVM ゲスト OS は TestDesktop, KvmGuest3, KvmGuest2 でした。
- KVM ゲスト OS を起動
>>> oPy27.call(sModuleName='mLibVirtConn', sClassName='LibVirtConn', sFuncName='domain_create', xFuncArgs={'sName': 'TestDesktop'}) 0
KVM ゲスト OS の TestDesktop を起動しました。
- KVM ゲスト OS を強制停止
>>> oPy27.call(sModuleName='mLibVirtConn', sClassName='LibVirtConn', sFuncName='domain_destroy', xFuncArgs={'xNameOrID': 'TestDesktop'}) 0
KVM ゲスト OS の TestDesktop を強制停止させました。(通常は shutdown コマンドで停止させて下さい)
0 件のコメント:
コメントを投稿