Автоматизация задач администрирования API VMware vSphere с использованием Python

    image

    В нашей компании активно используется платформа для виртуализации VMware vSphere. В ней живут тестовые среды продуктов, демонстрационные стенды, эмуляторы различных инфраструктур заказчиков и прочие не менее важные «виртуалки». Несмотря на достаточную мощность нашей инфраструктуры, доступ большого числа человек к управлению виртуальными машинами постоянно приводит к конфликтам и снижению производительности фермы. Разделение пулов между отделами (инженерами, тестировщиками, сейлами и разработчиками) проблему до конца не решает, поэтому периодически приходится разбираться, кто всем мешает и кто съел все ресурсы. При количестве виртуальных машин далеко за сотню сделать это вручную бывает проблематично, поэтому мы научились использовать API. VMware vSphere имеет довольно богатое API, которое незаслуженно слабо освещено на Хабре, хотя прикладная область применения довольна широка.

    В данной статье будут приведены примеры взаимодействия в рамках задач администрирования с помощью Python.

    Для Python есть библиотека под названием pyVmomi от самой VMware.


    Подготовка


    В папке проекта создадим конфигурационный файл config.txt следующего содержания:

    [VSphere]
    host=10.10.1.2
    user=admin@domain
    pwd=password

    Для его чтения используем модуль configparser.

    config = configparser.ConfigParser()
    config.read("config.txt")

    Чтобы подключиться к сфере, используются методы pyVim.connect.SmartConnect и pyVim.connect.SmartConnectNoSSL. Второй применяется для самоподписанных сертификатов.

    from pyVim.connect import SmartConnectNoSSL
    connection = SmartConnectNoSSL(**config["VSphere"])

    Список машин по месту на датасторах


    Предположим, на датасторах закончилось место. Эту проблему мы сейчас будем решать. Цель — получить список виртуальных машин, отсортированный по убыванию размера занятого места на датасторах. Также выведем максимальный размер файла, до которого может вырасти диск виртуальной машины, и количество места, занятого в гостевой системе.

    Получить список виртуальных машин можно следующим образом:

    from pyVmomi import vim
    
    def get_all_vms():
        content = connection.content
        container = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)
        return [VirtualMachine(managed_object_ref) for managed_object_ref in container.view]

    Как можно было заметить, возвращается список объектов класса VirtualMachine. Сейчас его и реализуем:

    class VirtualMachine:
        def __init__(self, machine_object):
            self.vm = machine_object
    
        @property
        def name(self):
            return self.vm.name
    
        @property
        def provisioned_space(self):
            return int(self.vm.summary.storage.committed + self.vm.summary.storage.uncommitted) / 1024**3
    
        @property
        def guest_disk_usage(self):
            return sum([int(i.capacity - i.freeSpace) for i in self.по размеру снапшотаvm.summary.vm.guest.disk]) / 1024**3
    
        @property
        def usage_storage(self):
            return int(self.vm.summary.storage.committed) / 1024**3
    
        def __repr__(self):
            return "{}  {:.2f}  {:.2f}  {:.2f}".format(self.name, self.provisioned_space,
                                                       self.guest_disk_usage, self.usage_storage)

    Вывод данных уже зависит от необходимости. Самое простое — вывести в консоль:

    for virtual_machine in sorted(get_all_vms(), key=lambda vm: vm.usage_storage, reverse=True):
        print(virtual_machine)

    Размеры и количество снапшотов


    С размерами виртуальных машин разобрались. Предположим, мы хотим узнать, сколько снапшотов имеет каждая виртуальная машина, и сколько места они занимают.

    Логика предыдущего примера сохраняется, только теперь наш класс VirtualMachine будет выглядеть так:

    class VirtualMachine:
        def __init__(self, machine_object):
            self.vm = machine_object
            self.snapshot_count, self.snapshot_size = self._snapshot_info()
    
        @property
        def name(self):
            return self.vm.name
    
        def _snapshot_info(self):
            disk_list = self.vm.layoutEx.file
            size = 0
            count = 0
            for disk in disk_list:
                if disk.type == 'snapshotData':
                    size += disk.size
                    count += 1
                ss_disk = re.search('0000\d\d', disk.name)
                if ss_disk:
                    size += disk.size
            return count, size / 1024**3
    
        def __repr__(self):
            return "{}  {:.2f}  {}".format(self.name, self.snapshot_size, self.snapshot_count)
    

    И вывод будет отсортирован уже по размеру или по количеству:

    for virtual_machine in sorted(get_all_vms(), key=lambda vm: vm.snapshot_size, reverse=True):
        print(virtual_machine)

    Восстановление снапшота


    Раз пошла речь про снапшоты, то поговорим об их восстановлении.

    Гипотетическая задача — восстановить последние созданные снапшоты, в названии которых присутствует строка infra.

    Для восстановления снапшота необходимо создать задачу RevertToSnapshot_Task().

    Сперва получим необходимый список машин:

    def get_vms(part_of_name):
        content = connection.content
        container = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)
        return [managed_object_ref for managed_object_ref in container.view if part_of_name in managed_object_ref.name]

    Для получения последнего созданного снапшота вернем последний элемент списка vm.snapshot.rootSnapshotList, отсортированного по полю createTime:

    def get_last_snapshot(vm):
        try:
            return sorted(vm.snapshot.rootSnapshotList, key=lambda snap: snap.createTime)[-1]
        except AttributeError:
            return None

    Теперь же можем восстановить этот снапшот:

    def restore_snapshot(snaphot_obj):
        task = snaphot_obj.snapshot.RevertToSnapshot_Task()
        WaitForTask(task, connection)

    Теперь все объединим:

    part_of_name = "infra"
    for vm in get_vms(part_of_name):
        last_snapshot = get_last_snapshot(vm)
        if last_snapshot:
            restore_snapshot(last_snapshot)

    Включение/выключение по списку


    Для выключения виртуальной машины необходимо создать задачу PowerOffVM_Task().

    Напишем функцию выключения машины, если она включена:

    def poweroff_if_enabled(vm):
        if vm.runtime.powerState == vim.VirtualMachinePowerState.poweredOn:
            vm.PowerOffVM_Task()

    Итоговый скрипт:

    part_of_name = "infra"
    for vm in get_vms(part_of_name):
        poweroff_if_enabled(vm)
    

    Такое выключение машины будет принудительным. Гораздо правильнее будет вызвать задачу ShutdownGuest():

    def shutdown_guest(vm):
        if vm.runtime.powerState == vim.VirtualMachinePowerState.poweredOn:
            vm.ShutdownGuest()

    В конце хотелось бы привести еще несколько полезных ссылок:

    • pyvmomi samples — примеры от самой VMware
    • pyvmomi community samples — репозиторий с примерами использования библиотеки, написанными сообществом
    • govmomi — пакет для языка goland. Его использует kubernetes
    • rbvmomi — ruby-интерфейс для vSphere API

    Если тема вызовет интерес, мы готовы ее продолжить и рассказать, как автоматизировать развертывание приложения от пуша в Git до создания виртуальной машины с работающим инстансом.

    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

    Продолжить тему?

    • 94,6%Продолжайте, пожалуйста35
    • 5,4%Не стоит, все и так очевидно2
    • +13
    • 2,9k
    • 3
    Avanpost
    59,10
    Безопасность начинается с управления доступом
    Поделиться публикацией

    Комментарии 3

      –1
      Хм… а стоит ли на питоне городить? Есть же VMWare PowerCLI. Очень удобно рулится через Powershell.
        +1

        Powershell, несомненно удобен, особенно Windows- администраторам, привыкшим его использовать. В нашем же случае, большая часть инфраструктуры линуксовая и питон нам "роднее", это первая причина. Вторая — эти скрипты — маленькая часть автоматизации тестовой лаборатории. Есть еще веб — страницы на которых отображается информация о машинах, мониторинг, информирование, ansible и т.д. А для решения таких задач питон подходит куда лучше.

        –1
        Соглашусь, Powershell весьма удобен. К примеру, снепшоты и размеры в одну строку:
        Get-VM | Get-Snapshot | Sort SizeGB -Descending | FT -Auto VM,Name,Created,SizeGB

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое