Pull to refresh

XEN: Простой скрипт для быстрого открытия VNC-консолей

Reading time 4 min
Views 5.2K

Постановка задачи


Описание проблемы


В работе активно используется 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, у меня она лежит в
/usr/lib64/python2.7/site-packages/xen/util/xmlrpcclient.py
Возможно в будущем, если будет время, я переделаю подключение ко 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
Tags:
Hubs:
+15
Comments 3
Comments Comments 3

Articles