Как стать автором
Обновить
0
Аванпост
Безопасность начинается с управления доступом

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

Время на прочтение4 мин
Количество просмотров20K

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

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

А в следующей статье рассмотрим администрирование с использованием Ansible.

Для 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 до создания виртуальной машины с работающим инстансом.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Продолжить тему?
96.25% Продолжайте, пожалуйста77
3.75% Не стоит, все и так очевидно3
Проголосовали 80 пользователей. Воздержались 6 пользователей.
Теги:
Хабы:
+13
Комментарии3

Публикации

Изменить настройки темы

Информация

Сайт
www.avanpost.ru
Дата регистрации
Дата основания
Численность
51–100 человек
Местоположение
Россия
Представитель
AvanpostID

Истории