本文共 21533 字,大约阅读时间需要 71 分钟。
yum install qemu-guest-agent(2)修改安装后的qemu-ga配置文件
#修改/etc/sysconfig/qemu-ga文件将 # Enable fsfreeze hook. See the --fsfreeze-hook option in "qemu-ga --help".FSFREEZE_HOOK_ENABLE=0改为# Enable fsfreeze hook. See the --fsfreeze-hook option in "qemu-ga --help".FSFREEZE_HOOK_ENABLE=1
#修改/etc/sysconfig/qemu-ga,注释掉BLACKLIST_RPC这一行,将所有功能开放将BLACKLIST_RPC="guest-file-open,guest-file-close,guest-file-read,guest-file-write,guest-file-seek,guest-file-flush"改为#BLACKLIST_RPC="guest-file-open,guest-file-close,guest-file-read,guest-file-write,guest-file-seek,guest-file-flush"(3)将虚拟机关机,在虚拟机配置文件libvirt.xml中的<devices>下面添加下述配置,并重新启动虚拟机
(4)测试是否正常
#得到虚拟机对应的domain id[root@node-12 ~]# virsh list Id 名称 状态---------------------------------------------------- 90 instance-0000209f running #使用命令进行测试[root@node-12 ~]# virsh qemu-agent-command 90 '{"execute":"guest-info"}'{"return":{"version":"0.12.1","supported_commands":[{"enabled":true,"name":"guest-set-vcpus"},{"enabled":true}...(5)freeze文件系统的方法
#直接用virsh命令,freeze文件系统[root@node-12 ~]# virsh qemu-agent-command 90 '{"execute":"guest-fsfreeze-freeze"}'{"return":1} #freeze后,可以查询当前虚拟机文件系统的状态,表明是frozen[root@node-12 ~]# virsh qemu-agent-command 90 '{"execute":"guest-fsfreeze-status"}'{"return":"frozen"} #thaw(解封)文件系统[root@node-12 ~]# virsh qemu-agent-command 90 '{"execute":"guest-fsfreeze-thaw"}'{"return":1} #thaw后,文件系统为解封状态[root@node-12 ~]# virsh qemu-agent-command 90 '{"execute":"guest-fsfreeze-status"}'{"return":"thawed"}
from commands import getstatusoutputimport loggerimport os, sys, statimport json import base64 import crypt import stringimport random import reimport socket########################Configure############################FILE_OPEN_READ="""{"execute":"guest-file-open", "arguments":{"path":"%s","mode":"r"}}""" FILE_OPEN_WRITE="""{"execute":"guest-file-open", "arguments":{"path":"%s","mode":"%s"}}""" FILE_READ="""{"execute":"guest-file-read", "arguments":{"handle":%s,"count":%d}}"""FILE_WRITE="""{"execute":"guest-file-write", "arguments":{"handle":%s,"buf-b64":"%s"}}""" FILE_CLOSE="""{"execute":"guest-file-close", "arguments":{"handle":%s}}""" class QemuQuestAgent: def __init__(self): self.__socketFileName = "" self.__totalSize = 0 self.__currentSize = 0 def setSocketFile(self, filename): self.socketFileName = filename if not os.path.exists(self.socketFileName): logger.error("%s do not exist!", self.socketFileName) return False return True def resetPassWord(self, newPassword): passwordFile = "/etc/shadow" content = self._QemuQuestAgent__guestFileRead(passwordFile) if not content.strip(): return False content = base64.standard_b64decode(content) user_array = re.split("\n",content) for iter,line in enumerate(user_array): info = line.split(":") if info[0] == "root": info[1] = self._QemuQuestAgent__generationPwd(newPassword) user_array[iter] = ":".join(info) break content = base64.standard_b64encode("\n".join(user_array)) write_count = self._QemuQuestAgent__guestFileWrite(passwordFile, content, "w+") if write_count > 0: logger.info("change password successfully!") return True else: return False def putFileToVM(self, fileName, vmFilePathName): if not os.path.exists(fileName): logger.error("%s do not exist" % (fileName)) return False if vmFilePathName[-1] == "/": vmFilePathName += fileName.split("/")[-1] filestats = os.stat(fileName) self.__totalSize = filestats[stat.ST_SIZE] if self.__totalSize <= 0: logger.error("%s is Empty!" % (fileName)) return False fd = open(fileName, "r") self.__currentSize = 0 total = 0 while True: content = fd.read(4096) total += 4096; self.__currentSize += len(content) #<=4096 content = base64.standard_b64encode(content) write_count = self._QemuQuestAgent__guestFileWrite(vmFilePathName, content, "a+") if write_count <= 0: fd.close() return False if total >= self.__totalSize: break fd.close() return True def processWrite(self): return (self.__currentSize, self.__totalSize) def __getResult(self, command, fileName = ""): resultStr = "" if fileName.strip(): self.socketFileName = fileName if not os.path.exists(self.socketFileName): return None; sockfd = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) server_address = self.socketFileName try: sockfd.connect(server_address) except socket.error, msg: logger.error("guestagent:%s,%s", socket.error, msg) return None try: sockfd.send(command) resultStr = sockfd.recv(10240) finally: sockfd.close() return None if not resultStr else json.loads(resultStr); def __generationPwd(self, pwd): salt=''.join(random.choice(string.ascii_letters + string.digits + "./") for _ in range(16)) return crypt.crypt(pwd, "$6$%s" % salt) def __guestFileRead(self, path): file_handle = -1 content = self._QemuQuestAgent__getResult(FILE_OPEN_READ % (path)) if not content: return "" file_handle = content["return"] if file_handle == -1: return "" file_content = self._QemuQuestAgent__getResult(FILE_READ % (file_handle,102400))["return"]["buf-b64"] self._QemuQuestAgent__getResult(FILE_CLOSE % file_handle) if not file_content: return "" else: return file_content def __guestFileWrite(self, path, content, mode): file_handle = -1 content = self._QemuQuestAgent__getResult(FILE_OPEN_WRITE % (path, mode)) if not content: return -1 file_handle = content["return"] if file_handle == -1: return -2 write_count = self._QemuQuestAgent__getResult(FILE_WRITE % (file_handle,content))["return"]["count"] self._QemuQuestAgent__getResult(FILE_CLOSE % file_handle) return write_count ########################test############################def testagent(): instance = QemuQuestAgent() if instance.setSocketFile("/var/lib/libvirt/qemu/test.agent"): if instance.resetPassWord("abc123"): return True if instance.putFileToVM("test.py", "/root/test.py"): return True return Falseif __name__ == '__main__': testagent()
#ifndef QEMUQUESTAGENT_H#define QEMUQUESTAGENT_H#include(2)qemuquestagent.cpp#include #include #include /*********************** * * * * qemu-ga --daemonize -m virtio-serial -p /dev/virtio-ports/org.qemu.guest_agent.0 * **********************//*************QemuQuestAgent*****************/class HostConnectVM;class ResetPassWord;class FileManager;class QemuQuestAgent{public: QemuQuestAgent(); ~QemuQuestAgent(); void getQGACommandAll(); void resetPassWord(); void fileOperation();private: HostConnectVM *hostVM; ResetPassWord *passWord; FileManager *fileManager; QString socketFileName;};/*************ResetPassWord*****************/class ResetPassWord{public: ResetPassWord(HostConnectVM *host); ~ResetPassWord(); int checkOldPassWord(const QString &password); int setNewPassWord(const QString &password);private: QString passwdFileRead(); bool passwdFileWrite(const QString &password); bool openFile(QString mode); void closeFile(); QString generationNewPassWord(const QString &password);private: int fileHandle; QString filePasswd; HostConnectVM *pwHost; QStringList lineContent;};/*************FileManager*****************/class FileManager{public: FileManager(HostConnectVM *host); ~FileManager(); int getFile(const QString &filePathName, const QString &localPath = ""); int putFile(const QString &localPathName, const QString &clientPathName); bool getFileContent(const QString &filename, const QString &localPathName); bool putFileContent(const QString &localName, const QString &clientName);private: int openFile(const QString &filename, const QString &mode);private: HostConnectVM *fmHost;};#endif // QEMUQUESTAGENT_H
#include(3)questagentcomponent.cpp socket通讯,发送命令返回结果#include #include "qemuquestagent.h"#include "questagentcomponent.h"#include "defineconstants.h"#include "jsonparse.h"#include "base64.h"/*************QemuQuestAgent*****************/QemuQuestAgent::QemuQuestAgent(){ socketFileName = "/var/lib/libvirt/qemu/test.agent"; hostVM = new HostConnectVM(socketFileName); passWord = new ResetPassWord(hostVM); fileManager = new FileManager(hostVM);}QemuQuestAgent::~QemuQuestAgent(){ if (hostVM) { delete hostVM; hostVM = NULL; } if (passWord) { delete passWord; passWord = NULL; } if (fileManager) { delete fileManager; fileManager = NULL; }}void QemuQuestAgent::getQGACommandAll(){ QString info = hostVM->getResult(GUEST_INFO); qDebug() << __FUNCTION__<<__LINE__ << info; if (info == "error2") { qDebug() << "can not conncet to the client of VM"; }}void QemuQuestAgent::resetPassWord(){ QString oldPassWord = "abc123"; QString newPassWord = "abc124"; int flag = passWord->checkOldPassWord(oldPassWord); if (flag == 1) { qDebug() << "old password is wrong"; } else if (flag == 0){ qDebug() << "password is right"; if (passWord->setNewPassWord(newPassWord) == 0) { qDebug() << "set newpassword succeed"; } else { qDebug() << "set newpassword failed"; } } else { //qDebug() << __LINE__ << "the client of VM is off"; }}void QemuQuestAgent::fileOperation(){ qDebug() << "---fileOperation---"; QString file = "/tmp/test1K.iso"; fileManager->getFile(file, "/tmp/abc/"); //fileManager->putFile("/tmp/abc/test1M.iso", "/tmp/");}/*************ResetPassWord*****************/ResetPassWord::ResetPassWord(HostConnectVM *host) : fileHandle(-1){ filePasswd = "/etc/shadow"; pwHost = host;}ResetPassWord::~ResetPassWord(){}int ResetPassWord::checkOldPassWord(const QString &password){ if (openFile("r") == false) { return -1; } QString fileContent = passwdFileRead(); closeFile(); lineContent.clear(); lineContent = fileContent.split("\n"); for (int index = 0; index < lineContent.size(); ++index) { QStringList fields = lineContent.at(index).split(":"); if (fields.at(0) == "root") { QStringList passwdList = fields.at(1).trimmed().split("$"); QString saltBuff = QString("$%1$%2").arg(passwdList[1]).arg(passwdList[2]); char *shadowPwd = crypt(password.toStdString().data(), saltBuff.toStdString().data()); if (!strcmp(shadowPwd, fields.at(1).trimmed().toStdString().data())) { //compare old and new password return 0; } else { return 1; } } } return false;}int ResetPassWord::setNewPassWord(const QString &password){ for (int index = 0; index < lineContent.size(); ++index) { QStringList fields = lineContent.at(index).split(":"); if (fields.at(0) == "root") { fields[1] = generationNewPassWord(password); lineContent[index] = fields.join(":"); break; } } QString newFileContent = ""; if (lineContent.size() > 0) { newFileContent = lineContent.join("\n"); } if (openFile("r+") == false && newFileContent.isEmpty()) { return -1; } if (passwdFileWrite(newFileContent) == false) { return 1; } lineContent.clear(); closeFile(); return 0;}QString ResetPassWord::passwdFileRead(){ QString resultStr = pwHost->getResult(FILE_READ.arg(fileHandle).arg(1400)); //qDebug() << "**********" << resultStr<<"****"; QMap resultMap = JsonParse::jsonParseEnter(resultStr); // {"return": {"buf-b64": "aGVsbG8gd29ybGQhCg==", "count": 13, "eof": true}} if (resultMap.count() != 3) { qDebug() << "JsonParse failed!" < getResult(FILE_WRITE.arg(fileHandle).arg(QString::fromStdString(outResult))); QMap resultMap = JsonParse::jsonParseEnter(resultStr); // {"return": {"count": 13, "eof": false}} qDebug() << "&&&" << resultMap.count() << resultMap["eof"] << resultMap["count"] << QString::fromStdString(outResult) << outResult.size(); if (resultMap.count() == 2 && resultMap["eof"] == "false") { qDebug() << "change password successed"; return true; } else { return false; }}bool ResetPassWord::openFile(QString mode){ QString resultStr = pwHost->getResult(FILE_OPEN.arg(filePasswd).arg(mode)); if (resultStr == "error2") { qDebug() << "can not conncet to the client of VM"; return false; } //qDebug() << "aoyang---------------" << resultStr; QMap resultMap = JsonParse::jsonParseEnter(resultStr); fileHandle = resultMap.begin().value().toInt(); if (fileHandle < 0) { return false; } return true;}void ResetPassWord::closeFile(){ pwHost->getResult(FILE_FLUSH.arg(fileHandle)); pwHost->getResult(FILE_CLOSE.arg(fileHandle));}QString ResetPassWord::generationNewPassWord(const QString &password){ char seqCode[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"; QString verifyCode = "$6$"; QTime time= QTime::currentTime(); qsrand(time.msec()+time.second()*1000); for(int i = 0; i < 16; i++) { int num = qrand() % strlen(seqCode); verifyCode += seqCode[num]; } QString shadowPwd = crypt(password.toStdString().data(), verifyCode.toStdString().data()); return shadowPwd;}/*************FileManager*****************/FileManager::FileManager(HostConnectVM *host){ fmHost = host;}FileManager::~FileManager(){}int FileManager::getFile(const QString &filePathName, const QString &localPath){ if (filePathName.isEmpty()) { return -1; } QFileInfo info(filePathName); QString locaFilename = localPath; if (localPath.isEmpty()) { locaFilename = QDir::currentPath(); locaFilename += "/"; locaFilename += info.fileName(); } else if (localPath.right(1) == "/"){ //path locaFilename += info.fileName(); } QFileInfo loaclInfo(locaFilename); QString dirName = loaclInfo.absolutePath(); QDir dir(dirName); if (!dir.exists()) { dir.mkpath(dirName); } //write content to file //qDebug() << "locaFilename=" << locaFilename << "filePathName=" < getResult(FILE_READ.arg(handle).arg(1400)); //qDebug() << "--------" << resultStr<<"---------"; QMap resultMap = JsonParse::jsonParseEnter(resultStr); // {"return": {"buf-b64": "aGVsbG8gd29ybGQhCg==", "count": 13, "eof": false}} if (resultMap.count() != 3) { qDebug() << "JsonParse failed!" < << QString::fromStdString(outResult); out << QString::fromStdString(outResult); file.flush(); if (resultMap["eof"] == "true") { file.close(); fmHost->getResult(FILE_CLOSE.arg(handle)); return true; } } } return false;}int FileManager::putFile(const QString &localPathName, const QString &clientPathName){ QFileInfo localFile(localPathName); if (!localFile.isFile()) { qDebug() << "file is not existed"; return -1; } //long fileSize = localFile.size(); QString clientFileName = clientPathName; if (clientPathName.right(1) == "/") { clientFileName += localFile.fileName(); } putFileContent(localPathName, clientFileName);}bool FileManager::putFileContent(const QString &localName, const QString &clientName){ QFile file(localName); long fileSize = file.size(); if (fileSize <= 0) { return false; } if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return false; } int handle = openFile(clientName, "w"); if (handle < 0) { return false; } int total = 0; do { string fileContent = file.read(10240).data(); total += 10240; string outResult = ""; Base64TransCode::Base64Encode(fileContent, &outResult); QString resultStr = fmHost->getResult(FILE_WRITE.arg(handle).arg(QString::fromStdString(outResult))); fmHost->getResult(FILE_FLUSH.arg(handle)); QMap resultMap = JsonParse::jsonParseEnter(resultStr); // {"return": {"count": 13, "eof": false}} //qDebug() << "&&&" << resultMap.count() << resultMap["eof"] << resultMap["count"]<< outResult.size(); if (resultMap.count() != 2 || resultMap["count"].toInt() <= 0) { qDebug() << "write file error"; fmHost->getResult(FILE_CLOSE.arg(handle)); return false; } }while(total < fileSize); fmHost->getResult(FILE_CLOSE.arg(handle));}int FileManager::openFile(const QString &filename, const QString &mode){ QString resultStr = fmHost->getResult(FILE_OPEN.arg(filename).arg(mode)); qDebug() << FILE_OPEN.arg(filename).arg(mode); if (resultStr == "error2") { qDebug() << "can not conncet to the client of VM"; return -2; } QMap resultMap = JsonParse::jsonParseEnter(resultStr); int fileHandle = resultMap.begin().value().toInt(); if (fileHandle <= 0) { qDebug() << "open file failed!"; return -1; } return fileHandle;}
#include(4)jsonparse.cpp 传输数据格式json的封装和解析/* See NOTES */#include #include #include #include #include "questagentcomponent.h"HostConnectVM::HostConnectVM(const QString &file){ socketFile = file;}HostConnectVM::~HostConnectVM(){}QString HostConnectVM::getResult(QString command, QString file){ if (!file.isEmpty()) { socketFile = file; } QString resultStr = ""; /* create a socket */ struct sockaddr_un address; address.sun_family = AF_UNIX; strcpy(address.sun_path, socketFile.toStdString().data()); sockfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sockfd == -1) { qDebug() << "create socket failed"; resultStr = "error1"; return resultStr; } /* connect to the server */ int result = connect(sockfd, (struct sockaddr *)&address, sizeof(address)); if(result == -1) { qDebug() << "connect socket failed"; resultStr = "error2"; return resultStr; } if((result = write(sockfd, command.toStdString().data(), command.length())) != command.length()) { qDebug() << "write socket failed"; resultStr = "error3"; return resultStr; } char buff[10240] = {0}; if ((result = read(sockfd, buff, 10240)) == -1) { qDebug() << "read socket failed"; resultStr = "error4"; return resultStr; } resultStr = buff; resultStr = resultStr.trimmed(); close(sockfd); return resultStr;}
#include "jsonparse.h"JsonParse::JsonParse(){}JsonParse::~JsonParse(){}QMap(5)base64.cpp base64将字符串以MIME BASE64编码,此种编码是为了使二进制数据可以通过非纯8-bit的传输层传输,可以让中文字或者图片也能在网络上顺利传输,例如电子邮件的主体。在BASE64编码后的字符串只包含英文字母大小写、阿拉伯数字、加号与反斜线,共64个基本字符,不包含其它特殊的字符,因而才取名BASE64。编码后的字符串比原来的字符串长度再加1/3左右。JsonParse::jsonParseEnter(const QString &str){ QMap map; map.clear(); if (str.trimmed().isEmpty()) { return map; } QScriptEngine engine; QScriptValue source = engine.evaluate("value="+str); QScriptValue valueReturn = source.property("return"); if (valueReturn.isObject()) { QScriptValueIterator it(valueReturn); while(it.hasNext()) { it.next(); map.insert(it.name(), it.value().toString()); } } else { map.insert("return", valueReturn.toString()); }#ifndef PRINT_DEBUG QMap ::const_iterator iter = map.constBegin(); for(;iter != map.constEnd(); iter++) { qDebug() << "---key=" << iter.key() << ", value=" << iter.value(); }#endif}
#include(6)main.cpp#include "base64.h"bool Base64TransCode::Base64Encode(const string& input, string* output){ string temp; temp.resize(modp_b64_encode_len(input.size())); // makes room for null byte // null terminates result since result is base64 text! int input_size = static_cast (input.size()); int output_size= modp_b64_encode(&(temp[0]), input.data(), input_size); if (output_size < 0) return false; temp.resize(output_size); // strips off null byte output->swap(temp); return true;}bool Base64TransCode::Base64Decode(const string& input, string* output){ string temp; temp.resize(modp_b64_decode_len(input.size())); // does not null terminate result since result is binary data! int input_size = static_cast (input.size()); int output_size = modp_b64_decode(&(temp[0]), input.data(), input_size); if (output_size < 0) return false; temp.resize(output_size); output->swap(temp); return true;}
#include#include "qemuquestagent.h"int main(int argc, char *argv[]){ QCoreApplication a(argc, argv); QemuQuestAgent w; //w.resetPassWord(); w.getQGACommandAll(); //w.fileOperation(); return a.exec();}
转载地址:http://gylai.baihongyu.com/