Постановка задачи
Описание проблемы
В работе активно используется Xen с HVM виртуализацией. Часто бывает нужно получить доступ к консоли виртуальных машин, причем в том числе и тем, у кого доступа на севера с Xenом нет. У Xenа для этого есть возможность создавать для каждой виртуальной машины VNC-консоль, но каждый раз подключаться через VNC вручную неудобно.
Задача
Сделать веб-страницу со списком запущенных виртуальных машин и внедренным в нее VNC-апплетом, который можно открыть по нажатию ссылки. По пути разобраться с тем, как можно работать с Xenом из Питона.
Что получилось
Список запущенных domU
Сама VNC-консоль
Как получилось
Я использовал Питон и легкий веб-фреймворк CherrPy.
Из чего состоит
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+:dddd", 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, у меня она лежит в
/usr/lib64/python2.7/site-packages/xen/util/xmlrpcclient.pyc
Возможно в будем, если будет время, я передалю подключение ко XEN-серверу через XenApi, что более правильно.
Класс для отображения веб-страницы:
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сли перейти на
<адрес сервера>/vnc
она отобразит список запущенных domU, если же передать ей нужный порт через слеш, например
<адрес сервера>/vnc/5900
она запустит нужную консоль. Консоли запускаются с помощюь выдранной из Proxmox VE функции на javascript. После открытия апплета еще одна функция из Proxmox VE подстраивает размеры нового окна под необходимые.
Конфиг вебсервера 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
Автор: sistemshik