Постановка задачи
Описание проблемы
В работе активно используется Xen с HVM виртуализацией. Часто бывает нужно получить доступ к консоли виртуальных машин, причем в том числе и тем, у кого доступа на севера с Xenом нет. У Xenа для этого есть возможность создавать для каждой виртуальной машины VNC-консоль, но каждый раз подключаться через VNC вручную неудобно.
Задача
Сделать веб-страницу со списком запущенных виртуальных машин и внедренным в нее VNC-апплетом, который можно открыть по нажатию ссылки. По пути разобраться с тем, как можно работать с Xenом из Питона.
Что получилось
Список запущенных domU

Сама VNC-консоль

Как получилось
Я использовал Питон и легкий веб-фреймворк CherrуPy.
Из чего состоит
vm_console.py # сам скрипт static # директория со статическими файлами static/table.htm # шаблон для списка domU, в который потом подставляется сам список с помощью интерполяции static/vnc.js # javascript для открытия нового окна с VNC-апплетом и подстраивания размеров окна под апплет static/vnc.htm # шаблон для нового окна с VNC-апплетом, в который нужные данные подставляются с помощью интерполяции static/tightvnc-jviewer.jar # java-апплет для подключения к VNC, взят с http://www.tightvnc.com/ static/styles.css # стили для таблицы со списком domU, взяты с http://veerle-v2.duoh.com/blog/comments/a_css_styled_table/ static/images # картинки для стилей таблицы static/images/bg_header.jpg static/images/bullet1.gif
Сам скрпит
Логика работы скрипта следующая:
По запросу веб-страницы Получить список запущенных domU и портов их VNC-консолей Отобразить этот список По нажатию на соответвующий порт Открыть новую страницу с внедренным в нее java VNC-апплетом Передать этому апплету нужный адрес и порт
Импортируем нужные модули: сам cherrypy, модуль для взаимодействия с XEN-сервером и модуль для регулярных выражений чтобы заматчить адрес и порт VNC-сервера:
import cherrypy from xen.util.xmlrpcclient import ServerProxy import re
Класс для получения списка запущенных domU и формирования таблицы:
class xen(): """Communicates with xen via rpc""" @staticmethod def get_domains(): """Gets a dictionary with 'Domain Name':'VNC host:port' structure""" server = ServerProxy('httpu:///var/run/xend/xmlrpc.sock') domains = server.xend.domains_with_state(True, 'all', 1) domain_list = {} for first_level in domains: # iterate through first level parameters for second_level in first_level: # iterate through second level parameters if second_level[0] == "name" and second_level[1] != "Domain-0": domain_list_current = second_level[1] if second_level[0] == "device": for third_level in second_level[1]: # iterate through third level subparameters if third_level[0] == "location" and re.match("\d+\.\d+\.\d+\.\d+\:\d\d\d\d", third_level[1]): domain_list[domain_list_current] = str(third_level[1]) return domain_list @staticmethod def create_domain_table(): """Creates table from domain list""" table = """<table id='mytable' cellspacing='0'><caption>List of active domUs</caption> <th scope="col" class="nobg">domU</th> <th scope="col">VNC host:port</th> """ domain_list = xen.get_domains() for k, v in domain_list.iteritems(): link = v.split(':', 1)[1] table += """ <tr> <th class="spec" scope="row">%s</th> <td><a href="javascript:vnc_console('/vnc/%s')" target='_blank'>%s</a></td> </tr> """ % (k, link, v) table += "</table>" return table
Он подключается к XEN-серверу через сокет, и вытаскивает из него спиок запущенных domU со множеством атрибутов. Затем из этих атрибутов вытаскиваются нужные: имя domU и адрес: порт VNC-сервера. После этого формируется таблица со списком запущенных domU.
Метод подключения я подсмотрел в идущей в поставке с ксеном утилите xm, у меня она лежит в
Возможно в будущем, если будет время, я переделаю подключение ко XEN-серверу более правильным способом через XenApi./usr/lib64/python2.7/site-packages/xen/util/xmlrpcclient.py
Класс для отображения веб-страницы:
class listvm(object): def index(self, port=None): """Just a stub""" return """<h1><a href="/vnc/">vnc</a></h1>""" index.exposed = True def vnc(self, port=None): """Show running vm's or open vnc applet""" if port: template = open("static/vnc.htm", 'r').read() return template % port else: template = open("static/table.htm", 'r').read() return template % xen.create_domain_table() vnc.exposed = True
Нас интересует функция vnc. Eсли перейти на
она отобразит список запущенных domU, если же ��ередать ей нужный порт через слеш, например<адрес сервера>/vnc
она запустит нужную консоль. Консоли запускаются с помощью выдранной из Proxmox VE функции на javascript. После открытия апплета еще одна функция из Proxmox VE подстраивает размеры нового окна под необходимые.<адрес сервера>/vnc/5900
Конфиг вебсервера cherrypy, здесь все тривиально:
server_config = { 'server.socket_host': '127.0.0.1', 'server.socket_port': 80, 'tools.staticdir.root': "/usr/local/vm_console", 'tools.staticdir.debug': True, } cherrypy.config.update(server_config) listvm_config = { '/static': {'tools.staticdir.on': True, 'tools.staticdir.dir': "static", } } cherrypy.tree.mount(listvm(), '/', config=listvm_config) cherrypy.engine.start() cherrypy.engine.block()
Хочу потыкать
Я выложил все на github, взять можно здесь: github.com/sistemshik/vm_console
